首页
关于
友链
Search
1
wlop 4K 壁纸 4k8k 动态 壁纸
1,386 阅读
2
Nacos持久化MySQL问题-解决方案
895 阅读
3
Docker搭建Typecho博客
733 阅读
4
滑动时间窗口算法
706 阅读
5
Nginx反向代理微服务配置
676 阅读
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
登录
Search
标签搜索
java
javase
docker
java8
springboot
thread
spring
分布式
mysql
锁
linux
redis
源码
typecho
centos
git
map
RabbitMQ
lambda
stream
少年
累计撰写
189
篇文章
累计收到
20
条评论
首页
栏目
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
页面
关于
友链
搜索到
30
篇与
的结果
2022-04-21
Synchronized
Atomic原子性提供了互斥访问。同一时刻只能由一个线程来操作。除了Atomic原子性,还有锁。jdk提供的锁主要分2类1、Synchronized:一种依赖JVM去实现锁的关键字,Synchronized,在这个对象作用的范围内,都是同一时刻,只能有一个线程去操作。注意是,作用对象的作用范围内。2、另一种jdk代码层面的锁,jdk里面提供了一个Lock的接口,主要是依赖特殊的CPU指令,实现类中比较有代表性的是ReentrantLock。Synchronized一种同步锁,修改的对象主要有4种:修饰代码块:大括号括起来的代码,也就是同步语句块,它的作用范围是大括号括起来的代码,作用对象是调用代码块的对象。修饰方法:被称为同步方法,作用范围为整个方法,作用对象是也是调用该方法的对象。修饰静态方法:作用范围整个静态方法,作用对象是这个类的所有对象。修饰类:修饰内容是后面Synchronized括号括起来的部分,作用对象也是这个类的所有对象。代码说明:一、启用不同进程,同一对象调用,调用同一方法。package com.yanxizhu.demo.concurrency.sync; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @description: Synchronized修饰代码块、修改方法,作用对象为调用对象 * 这里测试,同一对象,启动不同进程,调同一方法 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/20 22:44 * @version: 1.0 */ @Slf4j public class DemoSynchronizedOne { /** * 修饰代码块,大括号被称为 同步代码块, * 作用范围:代码块内 * 作用对象:调用代码块的对象 */ public void test1() { synchronized (this) { for (int i = 0; i < 10 ;i ++){ log.info("test1 ...i={}",i); } } } /** * 修饰方法,该方法被称为同步方 * 作为范围:整个test2方法 * 作用对象:调用代码块的对象 */ public synchronized void test2() { for (int i = 0; i < 10 ;i ++){ log.info("test2 ...i={}",i); } } public static void main(String[] args) { DemoSynchronizedOne demoSynchronized = new DemoSynchronizedOne(); //线程池 ExecutorService executorService = Executors.newCachedThreadPool(); /** * 说明: 为什么执行2次 * 如果不用线程池,下面2次调用都是同一线程,不能验证。 * 使用线程池,相当于用了2各进程去执行test1,不用等一个进程执行完,在执行第二个线程, * 这样才能看到同一个对象的不同进程的执行情况。 */ //-----------------------------------测试同一对象的方法test1------------------------------------------- // 测试1: executorService.execute(() -> { demoSynchronized.test1(); }); executorService.execute(() -> { demoSynchronized.test1(); }); /* 输出结果: 23:33:52.670 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=0 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=1 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=2 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=3 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=4 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=5 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=6 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=7 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=8 23:33:52.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=9 23:33:52.674 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=0 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=1 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=2 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=3 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=4 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=5 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=6 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=7 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=8 23:33:52.675 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test1 ...i=9*/ //-----------------------------------测试同一对象的方法test2------------------------------------------- // 测试2: executorService.execute(() -> { demoSynchronized.test2(); }); executorService.execute(() -> { demoSynchronized.test2(); }); /* 输出结果: 23:33:24.291 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=0 23:33:24.295 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=1 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=2 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=3 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=4 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=5 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=6 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=7 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=8 23:33:24.296 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=9 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=0 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=1 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=2 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=3 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=4 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=5 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=6 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=7 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=8 23:33:24.296 [pool-1-thread-2] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedOne - test2 ...i=9*/ executorService.shutdown(); } }二、启动不同进程,不同对象,调用同一方法package com.yanxizhu.demo.concurrency.sync; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * * @description: Synchronized修饰代码块、修改方法,作用对象为调用对象 * 这里测试,不同对象,启动不同进程,调同一方法 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/20 22:44 * @version: 1.0 */ @Slf4j public class DemoSynchronizedTwo { /** * 修饰代码块,大括号被称为 同步代码块, * 作用范围:代码块内 * 作用对象:调用代码块的对象 */ public void test1(int j) { synchronized (this) { for (int i = 0; i < 10 ;i ++){ log.info("test1 ...i={},j={}",i,j); } } } /** * 修饰方法,该方法被称为同步方 * 作为范围:整个test2方法 * 作用对象:调用代码块的对象 */ public synchronized void test2(int j) { for (int i = 0; i < 10 ;i ++){ log.info("test2 ...i={},j={}",i,j); } } public static void main(String[] args) { DemoSynchronizedTwo demoSynchronizedTwo = new DemoSynchronizedTwo(); DemoSynchronizedTwo demoSynchronizedTwo2 = new DemoSynchronizedTwo(); //线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //-----------------------------------测试同一对象的方法test1,作用代码块------------------------------------------- // executorService.execute(()->{ // demoSynchronizedTwo.test1(1); // demoSynchronizedTwo2.test1(2); // }); /* 输出结果: 23:28:57.763 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=0,j=1 23:28:57.768 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=1,j=1 23:28:57.768 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=2,j=1 23:28:57.768 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=3,j=1 23:28:57.768 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=4,j=1 23:28:57.768 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=5,j=1 23:28:57.768 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=6,j=1 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=7,j=1 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=8,j=1 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=9,j=1 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=0,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=1,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=2,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=3,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=4,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=5,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=6,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=7,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=8,j=2 23:28:57.769 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test1 ...i=9,j=2*/ /* * 结论:说明作用于同步代码,不同对象的调用是相互不影响的 * */ //-----------------------------------测试同一对象的方法test2,作用方法------------------------------------------- executorService.execute(()->{ demoSynchronizedTwo.test2(1); demoSynchronizedTwo2.test2(2); }); /* 输出结果: 23:34:56.130 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=0,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=1,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=2,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=3,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=4,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=5,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=6,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=7,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=8,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=9,j=1 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=0,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=1,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=2,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=3,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=4,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=5,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=6,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=7,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=8,j=2 23:34:56.135 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedTwo - test2 ...i=9,j=2*/ /* * 结论:说明作用于方法,不同对象的调用是相互不影响的 * */ executorService.shutdown(); } }1和2对别结论:修饰带块和修改方法对别结论1、当一个方法内都是用同步代码块修饰的,和修饰方法是一样的。例如上面的: public void test1(int j) { synchronized (this) { for (int i = 0; i < 10 ;i ++){ log.info("test1 ...i={},j={}",i,j); } } } 等同与下面的修饰方法: public synchronized void test2(int j) { for (int i = 0; i < 10 ;i ++){ log.info("test2 ...i={},j={}",i,j); } }2、修饰静态代码块和修饰方法,作用对象都是调用对象。3、如果某个子类继承了上面的类,子类种test2方法是不带synchronized关键字的,因为synchronized不输入方法申明的一部分,如果子类想使用,则需要显示自己加synchronized。三、不同对象调用同一方法,synchronized修改类和方法:package com.yanxizhu.demo.concurrency.sync; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * * @description: Synchronized修饰静态方法、类 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/20 22:44 * @version: 1.0 */ @Slf4j public class DemoSynchronizedThredd { //修饰类 public static void test1(int j) { synchronized (DemoSynchronizedThredd.class) { for (int i = 0; i < 10 ;i ++){ log.info("test1 ...i={},j={}",i,j); } } } //修饰静态方法 public static synchronized void test2(int j) { for (int i = 0; i < 10 ;i ++){ log.info("test2 ...i={},j={}",i,j); } } public static void main(String[] args) { DemoSynchronizedThredd demoSynchronizedTwo = new DemoSynchronizedThredd(); DemoSynchronizedThredd demoSynchronizedTwo2 = new DemoSynchronizedThredd(); //线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //-----------------------------------测试同一对象的方法test1,作用代码块------------------------------------------- executorService.execute(()->{ demoSynchronizedTwo.test1(1); demoSynchronizedTwo2.test1(2); }); /* 输出结果: 23:49:32.176 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=0,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=1,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=2,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=3,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=4,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=5,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=6,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=7,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=8,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=9,j=1 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=0,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=1,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=2,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=3,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=4,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=5,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=6,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=7,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=8,j=2 23:49:32.181 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test1 ...i=9,j=2*/ //-----------------------------------测试同一对象的方法test2,作用方法------------------------------------------- /* executorService.execute(()->{ demoSynchronizedTwo.test2(1); demoSynchronizedTwo2.test2(2); });*/ /* 输出结果: 23:47:13.674 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=0,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=1,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=2,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=3,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=4,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=5,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=6,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=7,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=8,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=9,j=1 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=0,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=1,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=2,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=3,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=4,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=5,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=6,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=7,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=8,j=2 23:47:13.681 [pool-1-thread-1] INFO com.yanxizhu.demo.concurrency.sync.DemoSynchronizedThredd - test2 ...i=9,j=2*/ executorService.shutdown(); /** * 说明:修饰类和修改静态方法是一样的 */ } }结论:修改类和静态方法,作用效果是一样的。测试:之前计数通过Atomic原子保证互斥性,现在通过Synchronized保证互斥性。package com.yanxizhu.demo.concurrency.sync; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全,不正确的 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/19 19:28 * @version: 1.0 */ @ThreadSafety @Slf4j public class DemoSemaphoreAndCountDownLatch { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; //累加总和 private static int count = 0; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); add(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("累加结果为count=【{}】",count); } /** * 累加 */ private synchronized static void add(){ count++; } }原子性对比synchronized:不可中断锁,适合竞争不激烈,可读性好Lock:可中断锁,多样化同步,竞争激烈时能维持常态Atomic:竞争激烈时能维持常态,比Lock性能好;只能同步一个值
2022年04月21日
163 阅读
0 评论
1 点赞
2022-04-20
原子性-Atomic类常见的使用
1、(信号量)Semaphore+(闭锁)CountDownLatch+(常用源自类)AtomicIntegerpackage com.yanxizhu.demo.concurrency.atomic; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; /** * @description: 线程安全 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/19 20:05 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoSemaphoreAndCountDownLatchAndAtomic { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; //累加总和 private static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(clientsTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(concurrencyTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); add(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("累加结果为count=【{}】",count.get()); } /** * 累加 */ private static void add(){ //说明:incrementAndGet、getAndIncrement类似,i++与++i count.incrementAndGet(); count.getAndIncrement(); } }运行结果:累加结果为count=【10000】2、AtomicReferencepackage com.yanxizhu.demo.concurrency.atomic; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicReference; /** * @description: AtomicReference * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/20 21:09 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoAtomicReference { public static AtomicReference<Integer> count = new AtomicReference<>(0); public static void main(String[] args) { count.compareAndSet(0, 2); count.compareAndSet(0, 1); count.compareAndSet(1, 3); count.compareAndSet(2, 4); count.compareAndSet(3, 5); log.info("count结果为【{}】",count.get()); } }运行结果:count结果为【4】3、AtomicIntegerFieldUpdaterpackage com.yanxizhu.demo.concurrency.atomic; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; /** * @description: AtomicIntegerFieldUpdater,原子性修改 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/20 21:17 * @version: 1.0 */ @Slf4j public class DemoAtomicIntegerFieldUpdater { private static AtomicIntegerFieldUpdater<DemoAtomicIntegerFieldUpdater> updater = AtomicIntegerFieldUpdater.newUpdater(DemoAtomicIntegerFieldUpdater.class, "count"); @Getter public volatile int count = 100; private static DemoAtomicIntegerFieldUpdater demoAtomicIntegerFieldUpdater = new DemoAtomicIntegerFieldUpdater(); public static void main(String[] args) { if(updater.compareAndSet(demoAtomicIntegerFieldUpdater, 100, 200)) { log.info("updater succcess1,{}", demoAtomicIntegerFieldUpdater.getCount()); } if(updater.compareAndSet(demoAtomicIntegerFieldUpdater, 100, 200)) { log.info("updater succcess2,{}", demoAtomicIntegerFieldUpdater.getCount()); }else { log.info("updater fail,{}", demoAtomicIntegerFieldUpdater.getCount()); } } }运行结果:updater succcess1,200 updater fail,2004、AtomicStampedReference主要用于解决CAS中ABA问题,主要是AtomicStampedReference类中compareAndSet方法多了一个stamp的比较。stamp是每次更新来维护的。 public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { Pair<V> current = pair; return expectedReference == current.reference && expectedStamp == current.stamp && ((newReference == current.reference && newStamp == current.stamp) || casPair(current, Pair.of(newReference, newStamp))); } 5、LongAdderJDK1.8后新增了LongAdder。AtomicLong:是基于 CAS 方式自旋更新的;LongAdder: 是把 value 分成若干cell,并发量低的时候,直接 CAS 更新值,成功即结束。并发量高的情况,CAS更新某个cell值和需要时对cell数据扩容,成功结束;更新失败自旋 CAS 更新 cell值。取值的时候,调用 sum() 方法进行每个cell累加。AtomicLong: 包含有原子性的读、写结合的api;LongAdder :没有原子性的读、写结合的api,能保证结果最终一致性。低并发:低并发场景AtomicLong 和 LongAdder 性能相似。高并发:高并发场景 LongAdder 性能优于 AtomicLong。6、AtomicLongArray主要用于原子修改数组 // 下标, 期望值 更新值 public final boolean compareAndSet(int i, long expectedValue, long newValue) { return AA.compareAndSet(array, i, expectedValue, newValue); }通过传入下标、期望值、要更新的值进行修改。7、AtomicBoolean public final boolean compareAndSet(boolean expectedValue, boolean newValue) { return VALUE.compareAndSet(this, (expectedValue ? 1 : 0), (newValue ? 1 : 0)); }package com.yanxizhu.demo.concurrency.atomic; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; /** * @description: 结果,最后只会执行一次 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/20 22:05 * @version: 1.0 */ @Slf4j public class DemoAtomicBoolean { private static AtomicBoolean isHappen = new AtomicBoolean(false); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(clientsTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(concurrencyTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); test(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("isHappen结果为count=【{}】",isHappen.get()); } public static void test() { //从false变成true是一次原子操作,只会执行一次 if(isHappen.compareAndSet(false, true)) { log.info("execute .. {}", isHappen); } } }运行结果:execute .. true isHappen结果为count=【true】
2022年04月20日
166 阅读
0 评论
2 点赞
2022-04-20
AtomicStampedReference解决CAS中ABA问题
解决CAS的ABA问题CAS虽然高效的实现了原子性操作,但是也存在一些缺点,主要表现在以下三个方面。什么是ABA问题比如:线程1从主存中读取值A,另一个线程2也从主存中读取值A,此时线程2将主存值修改成了B,然后线程2又将主存值修改成了A,这时候线程1进行CAS操作发现内存中仍然是A,然后线程1操作成功,这是不正确的。如何解决ABA问题通过AtomicStampedReference的compareAndSet方法进行处理,这里的compareAndSet比一般的多了一个stamp的比较。源码如下: public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { Pair<V> current = pair; return expectedReference == current.reference && expectedStamp == current.stamp && ((newReference == current.reference && newStamp == current.stamp) || casPair(current, Pair.of(newReference, newStamp))); }多了一个stamp的比较,stamp是每次更新来维护的。
2022年04月20日
172 阅读
0 评论
3 点赞
2022-04-19
并发及CAS
计算机架构CPU多级缓存为什么需要CPU cacheCPU的频率太快了,快到主存跟不上,这样在处理器时钟周期内,CPU常常需要等待主存,浪费资源。所以cache的出现,是为了缓解CPU和内存之间速度的不匹配问题(结构:cpu->cache->memory)。CPU cache有什么意义1)时间局部性:如果某个数据被访问,那么在不久的将来它很可能被再次访问2)空间局部性:如果某个数据被访问,那么与它相邻的数据很快也可能被访问;CPU 多级缓存一致性(MESI)CPU缓存4种状态M:被修改状态,指该缓存行只被缓存在该CPU的缓存中,并且是被修改过的。因此与主存中的数据是不一致的,该缓存行中的内存需要再未来的某个时间点写会主存。这个时间点是允许其它CPU读取主存中相应的内存之前,当这里面的值被写会主存之后该缓存行的状态会变成E独享状态。E:独享状态,指缓存行只被缓存在该CPU的缓存中,它是未被修改过的,是和主存的数据一致的,这个状态可以在任何时刻,当有其它CPU读取该内存时变成S共享状态。当CPU修改该缓存行内容时,状态变成M状态。S:共享状态,意味该缓存行可能被多个CPU缓存,并且各CPU缓存中的数据与主存中的数据一致,当有一个CPU修改该缓存行时,其它CPU中该缓存行,是可以被作废的,变成I无效状态。I:无效状态,代表缓存无效,可能有其它CPU修改了该缓存行。引起CPU缓存状态变化的4种操作local read:读本地缓存中的数据local write:将数据写到本地的缓存里面remote read:将主内中的数据读取到本地缓存中remote write:将本地缓存中数据写到主存里面MESI协议:CPU缓存数据有4种状态,引起CPU缓存转变的操作也有4种,因此本质就是要理解这16种操作状态的关系,可以通过下图表示:重点理解1、CPU缓存是为了减少CPU读写共享主存的次数。2、除了I状态,其它三种状态都是可以被读取的。3、只有再M和E状态才能写。4、当为S状态时,必须将该缓存行变为无效状态,一般通过广播方式完成,此时不允许不同的CPU同时修改该缓存行,即使修改该缓存行不同位置的数据也是不允许的,这里主要解决缓存一致性的问题。5、只有M和E状态可以写,如果是S状态需要变为I状态。6、一个处于M装的缓存行,需要时刻监听所有试图读该缓存行,相对有主存的操作,这种操作必须将缓存行写会到主存,并将状态变为S状态之前,被延迟执行。7、S状态的缓存行,监听所有试图将该缓存行无效或独享该缓存行的请求,并将缓存行变为无效。8、处于E状态的缓存行,需要监听其它读该缓存行的操作,一旦有该缓存行的操作,那么该缓存行需要变为S状态。因此对于M和E状态的数据总是精确的,和缓存行的状态是真正一致的。S状态可能是非一致的。如果一个缓存将处于S状态的数据作废了,另一个缓存实际上可能已经独享了该缓存行,但是该缓存不会把缓存行升迁为E状态,因为其它不会广播该作废的通知,同样由于缓存没有缓存该COPY的数量,因此也无法确定自己是否独享了该缓存行。E状态更像一种投机的优化,因为当一个CPU想修改一个处于S共享状态的缓存行,总线事务需要将所有copy该缓存行缓存的值变成I状态才行。修改E状态的CPU缓存不需要总线事务。JAVA内存模型抽象结构图JAVA内存模型8个操作8种同步操作lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作write(写入):作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中同步规则如果要把一个变量从主内存中复制到工作内存,就需要按顺寻地执行read和load操作,如果把变量从工作内存中同步回主内存中,就要按顺序地执行store和write操作。但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行不允许read和load、store和write操作之一单独出现不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)compareAndSetInt举例一package com.yanxizhu.demo.concurrency.atomic; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; /** * @description: 线程安全 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/19 20:05 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoSemaphoreAndCountDownLatchAndAtomic { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; //累加总和 private static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(clientsTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(concurrencyTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); add(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("累加结果为count=【{}】",count.get()); } /** * 累加 */ private static void add(){ //说明:incrementAndGet、getAndIncrement类似,i++与++i count.incrementAndGet(); count.getAndIncrement(); } }源码解析count.incrementAndGet();public final int incrementAndGet() { return U.getAndAddInt(this, VALUE, 1) + 1; }@HotSpotIntrinsicCandidate public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!weakCompareAndSetInt(o, offset, v, v + delta)); return v; }weakCompareAndSetInt(o, offset, v, v + delta)@HotSpotIntrinsicCandidate public final boolean weakCompareAndSetInt(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); }compareAndSetInt(o, offset, expected, x)@HotSpotIntrinsicCandidate public final native boolean compareAndSetInt(Object o, long offset, int expected, int x);nativenative标识,说明是Java底层操作方法。重点说明@HotSpotIntrinsicCandidate /** * o: 当前对象,上面的count * offset: 当前值 (例如2+1),offset=2 * delta: (例如2+1),delta=1 **/ public final int getAndAddInt(Object o, long offset, int delta) { int v; do { //v:底层获取的值,如果没有其它线程修改,理论应该是2 v = getIntVolatile(o, offset); //重点: // 1)、当没有其它线程修改底层值时: // o这个对象,当前值offset=2与底层值v=2相等,则把底层值更新为(底层值v=2 + 增加值delta=1 = 最后就等于3) // // 2)、如果此有其它线程修改了底层值v(例如修改为v=4): // 此时低层值v=4与当前值offset=2不相等,则重新从count对象取出当前值offset=4, // 再判断当前值offset=4与底层值v=4相等,然后再讲底层值修改为(低层值v=4 + 增加值delta= 最后就登陆5), // 如果一直有其它线程修改底层值v,导致当前值offset与底层值v一直不相等,则一直循环上面的操作。 } while (!weakCompareAndSetInt(o, offset, v, v + delta)); return v; }CAS就是compareAndSet的缩写。底层值其实就是计算机的主内存,当前值就是JMM模型中工作内存值。特别说明JDK1.8后新增了LongAdder。AtomicLong:是基于 CAS 方式自旋更新的;LongAdder: 是把 value 分成若干cell,并发量低的时候,直接 CAS 更新值,成功即结束。并发量高的情况,CAS更新某个cell值和需要时对cell数据扩容,成功结束;更新失败自旋 CAS 更新 cell值。取值的时候,调用 sum() 方法进行每个cell累加。AtomicLong: 包含有原子性的读、写结合的api;LongAdder :没有原子性的读、写结合的api,能保证结果最终一致性。低并发:低并发场景AtomicLong 和 LongAdder 性能相似。高并发:高并发场景 LongAdder 性能优于 AtomicLong。
2022年04月19日
294 阅读
0 评论
3 点赞
2022-03-19
线程八锁
线程八锁package com.yanxizhu; /* * 题目:判断打印的 "one" or "two" ? * * 1. 两个普通同步方法,两个线程,标准打印, 打印? //one two * 2. 新增 Thread.sleep() 给 getOne() ,打印? //one two * 3. 新增普通方法 getThree() , 打印? //three one two * 4. 两个普通同步方法,两个 Number 对象,打印? //two one * 5. 修改 getOne() 为静态同步方法,打印? //two one * 6. 修改两个方法均为静态同步方法,一个 Number 对象? //one two * 7. 一个静态同步方法,一个非静态同步方法,两个 Number 对象? //two one * 8. 两个静态同步方法,两个 Number 对象? //one two * * 线程八锁的关键: * ①非静态方法的锁默认为 this, 静态方法的锁为 对应的 Class 实例 * ②某一个时刻内,只能有一个线程持有锁,无论几个方法。 */ public class TestThread8Monitor { public static void main(String[] args) { Number number = new Number(); Number number2 = new Number(); new Thread(new Runnable() { @Override public void run() { number.getOne(); } }).start(); new Thread(new Runnable() { @Override public void run() { //number.getTwo(); number2.getTwo(); } }).start(); /*new Thread(new Runnable() { @Override public void run() { number.getThree(); } }).start();*/ } } class Number{ public static synchronized void getOne(){//Number.class try { Thread.sleep(3000); } catch (InterruptedException e) { } System.out.println("one"); } public synchronized void getTwo(){//this System.out.println("two"); } public void getThree(){ System.out.println("three"); } }一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用 其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻 内,只能有唯一一个线程去访问这些synchronized方法锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的 synchronized方法加个普通方法后发现和同步锁无关换成两个对象后,不是同一把锁了,情况立刻变化。都换成静态同步方法后,情况又变化所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实 例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获 取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实 例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非 静态同步方法释放锁就可以获取他们自己的锁。所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对 象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个 静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取 锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同 步方法之间,只要它们同一个类的实例对象!
2022年03月19日
192 阅读
0 评论
6 点赞
2022-03-19
ScheduledThreadPool线程调度
ScheduledThreadPool线程调度package com.yanxizhu; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /* * 一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。 * * 二、线程池的体系结构: * java.util.concurrent.Executor : 负责线程的使用与调度的根接口 * |--**ExecutorService 子接口: 线程池的主要接口 * |--ThreadPoolExecutor 线程池的实现类 * |--ScheduledExecutorService 子接口:负责线程的调度 * |--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService * * 三、工具类 : Executors * ExecutorService newFixedThreadPool() : 创建固定大小的线程池 * ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。 * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程 * * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。 */ public class TestScheduledThreadPool { public static void main(String[] args) throws Exception { ScheduledExecutorService pool = Executors.newScheduledThreadPool(5); for (int i = 0; i < 5; i++) { Future<Integer> result = pool.schedule(new Callable<Integer>(){ @Override public Integer call() throws Exception { int num = new Random().nextInt(100);//生成随机数 System.out.println(Thread.currentThread().getName() + " : " + num); return num; } }, 1, TimeUnit.SECONDS); System.out.println(result.get()); } pool.shutdown(); } }
2022年03月19日
176 阅读
0 评论
5 点赞
2022-03-19
Executor线程池
Executors线程池package com.yanxizhu; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /* * 一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。 * * 二、线程池的体系结构: * java.util.concurrent.Executor : 负责线程的使用与调度的根接口 * |--**ExecutorService 子接口: 线程池的主要接口 * |--ThreadPoolExecutor 线程池的实现类 * |--ScheduledExecutorService 子接口:负责线程的调度 * |--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService * * 三、工具类 : Executors * ExecutorService newFixedThreadPool() : 创建固定大小的线程池 * ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。 * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程 * * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。 */ public class TestThreadPool { public static void main(String[] args) throws Exception { //1. 创建线程池 ExecutorService pool = Executors.newFixedThreadPool(5); List<Future<Integer>> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Future<Integer> future = pool.submit(new Callable<Integer>(){ @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i <= 100; i++) { sum += i; } return sum; } }); list.add(future); } pool.shutdown(); for (Future<Integer> future : list) { System.out.println(future.get()); } /*ThreadPoolDemo tpd = new ThreadPoolDemo(); //2. 为线程池中的线程分配任务 for (int i = 0; i < 10; i++) { pool.submit(tpd); } //3. 关闭线程池 pool.shutdown();*/ } // new Thread(tpd).start(); // new Thread(tpd).start(); } class ThreadPoolDemo implements Runnable{ private int i = 0; @Override public void run() { while(i <= 100){ System.out.println(Thread.currentThread().getName() + " : " + i++); } } }
2022年03月19日
146 阅读
0 评论
1 点赞
2022-03-19
ReadWriteLock读写锁
读写锁package com.yanxizhu; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @description: 读写锁(互斥锁) * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/19 15:23 * @version: 1.0 */ public class ReadWriteDemo { public static void main(String[] args) { ReadWriteTest readWriteTest = new ReadWriteTest(); new Thread(()->{ readWriteTest.write((int) (Math.random()*101)); },"写锁").start(); for(int i=1;i<50;i++){ new Thread(()->{ readWriteTest.get(); },"读锁").start(); } } } class ReadWriteTest{ int num =0; private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //读 public void get(){ readWriteLock.readLock().lock(); try{ System.out.println(num+"=="+Thread.currentThread().getName()); }finally { readWriteLock.readLock().unlock(); } } //写 public void write(int i){ readWriteLock.writeLock().lock(); try{ this.num=i; }finally { readWriteLock.writeLock().unlock(); } } }
2022年03月19日
135 阅读
0 评论
5 点赞
2022-03-19
线程按序交替
线程按序交替package com.yanxizhu; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @description: 线程按序交替 * @date: 2022/3/19 14:47 * @version: 1.0 */ public class PrintInfo { public static void main(String[] args) { print print = new print(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<5;i++){ try { print.printA(i); } catch (InterruptedException e) { e.printStackTrace(); } } } },"A").start(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<5;i++){ try { print.printB(i); } catch (InterruptedException e) { e.printStackTrace(); } } } },"B").start(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<5;i++){ try { print.printC(i); } catch (InterruptedException e) { e.printStackTrace(); } } } },"C").start(); } } class print{ private int num =1; Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); public void printA(int i) throws InterruptedException { lock.lock(); try{ if(num != 1){ condition1.await(); } System.out.println("A=="+Thread.currentThread().getName()+"====i="+i); num=2; condition2.signal(); }finally { lock.unlock(); } } public void printB(int i) throws InterruptedException { lock.lock(); try{ if(num != 2){ condition2.await(); } System.out.println("B=="+Thread.currentThread().getName()+"====i="+i); num=3; condition3.signal(); }finally { lock.unlock(); } } public void printC(int i) throws InterruptedException { lock.lock(); try{ if(num != 3){ condition3.await(); } System.out.println("C=="+Thread.currentThread().getName()+"====i="+i); num=1; condition1.signal(); }finally { lock.unlock(); } } }打印结果:A==A====i=1 B==B====i=1 C==C====i=1 A==A====i=2 B==B====i=2 C==C====i=2 A==A====i=3 B==B====i=3 C==C====i=3 A==A====i=4 B==B====i=4 C==C====i=4
2022年03月19日
130 阅读
0 评论
3 点赞
1
2
3
4