理解 Java synchronized
来源:互联网 发布:js 相对路径 绝对路径 编辑:程序博客网 时间:2024/06/04 19:55
多线程开发离不开锁机制,现在的Java语言中,提供了2种锁,一种是语言特性提供的内置锁,还有一种是 java.util.concurrent.locks 包中的锁。对于synchronized的一些基本概念这里就不重复了,很多博客都写到了。这篇文章针对一个例子,讲一下我的理解。
这是一个调用同步方法的同时,调用该对象非同步方法(但是内部含有同步块)的例子
package tmp;/** * Created by Gracecoder on 2017/11/24. */public class Service { private String anyString = new String(); public void a(){ try { synchronized (anyString) { System.out.println("a begin"); Thread.sleep(3000); System.out.println("a end"); } }catch (Exception e) { e.printStackTrace(); } } synchronized public void b() { System.out.println("b begin");// synchronized (anyString) {// anyString = new String("hello");// System.out.println(anyString);// } System.out.println("b end"); }}
package tmp;/** * Created by Gracecoder on 2017/11/24. */public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.a(); }}
package tmp;/** * Created by Gracecoder on 2017/11/24. */public class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.b(); }}
package tmp;/** * Created by Gracecoder on 2017/11/24. */public class Run { public static void main(String[] args){ Service service = new Service(); ThreadA a = new ThreadA(service); ThreadB b = new ThreadB(service); a.setName("A"); a.start(); b.setName("B"); b.start(); }}
运行结果:a beginb beginb enda end
运行这段代码首先线程A先获取成员变量anyString的内置锁,然后线程B访问同步方法,获取当前对象service的锁,这里anyString是对象service的成员变量,结果显示它们异步调用了。
按照我一开始的想法,如果反一下,由线程B先访问同步方法,获取当前对象service的锁之后,其他线程是否能获取其对象成员的锁? 我觉得 不能!但是通过运行代码验证,发现就算B先获得service的锁,A依旧能获得其成员anyString的锁,它们仍然是异步调用!
就很疑惑,我们获取一个对象的锁,但是不代表我们拥有其成员域对象的锁!
小结论:
每个对象都可以用作一个实现同步的锁,这些锁被称为内置锁!
对象的内置锁和对象的状态之间没有内在的关联,虽然大多数类都讲内置锁用作一种有效的加锁机制,但对象的域并不一定通过内置锁来保护。当获取到与对象关联的内置锁时,并不能阻止其他线程访问该对象,只能阻止其他线程获取同一个锁!
那显然每个对象都有自己的内置锁,尽管anyString是service的成员域,但它们两各自的内置锁也是不同的。所以就算反过来,B先获取this(synchronized方法相当于同步块synchronized(this))对象的锁,A还是可以获取anyString的锁。除非我们在B的同步方法中,再次请求获取anyString对象的锁,那就会同步,阻塞到A完成了。
这里还有一个类锁的概念,在synchronized同步方法前面加个static,那么访问该方法,就要获取当前类的锁。
//同步的类方法 synchronized public static void printA() { //todo }
注意:同样的,类锁和对象锁也不存在关联,它们是不同的锁。类锁并不包括该类具体对象的锁,如同对象锁并不包括其对象域的锁。在具体代码中,如果线程A先调用同步类方法(获取了类锁),线程B这时候调用同步方法,调用同步方法的前提是获得当前对象锁,而此时当前对象锁空闲,所以可以异步执行。如果还有一个线程C要调用另一个同步类方法或者同步方法,则必须等A或B执行完毕后,才能获得锁,同步执行!
而类锁对类的所有对象实例起作用的本质是:
实例对象如果要调用synchronized类方法,那么就要获取类锁,此时不同对象获取的类锁都是同一个,那么就会产生同步!
总结:
synchronized 同步的本质就是:是否使用同一个对象监视器
任何对象都有一个自己的内置锁,同步或者异步,主要就是看多线程竞争的是否是同一把锁。区分这一点才是关键,当获取到与对象关联的内置锁时,并不能阻止其他线程访问该对象,只能阻止其他线程获取同一个锁!
synchronized(非this对象x)格式的写法是将x对象本身作为“对象监视器”,这样就可以得出以下3个结论:
- 当多个线程同时执行synchronized(x){}同步代码块时呈同步效果(竞争this当前对象的锁)
- 当其他线程执行x对象中synchronized同步方法时呈同步效果(竞争x对象)
- 当其他线程执行x对象方法里面的synchronized(this)代码块时也是同步
需要注意的是:如果其他线程调用不加synchronized关键字的方法时,还是异步调用,因为其他线程没有去竞争锁。
线程安全包括可见性和原子性,synchronized实现了原子性,同时间接现实可见性。而volatile只有可见性,没有原子性。
- java thread synchronized 理解
- java thread synchronized 理解
- java thread synchronized 理解
- java synchronized关键字理解
- java synchronized理解
- java中的synchronized理解
- java thread synchronized 理解
- Java-synchronized深入理解
- java中的synchronized理解
- java synchronized 理解
- Java synchronized的理解
- Java synchronized 理解
- 理解 Java synchronized
- Java 中synchronized的理解
- java synchronized锁的理解
- java synchronized的初步理解
- 对Java关键字synchronized的一些理解
- 对java中synchronized的一点理解
- GC日志
- ES6--异步操作之promise(续)
- RecyclerView使用时,解决Item显示不全问题
- 导入iOS-Echarts库运行时报too many errors emitted, stopping now [-ferror-l
- awk详解
- 理解 Java synchronized
- 微信小程序蓝牙通讯蓝牙模块demo
- Node.js学习-web框架-2-中间件
- 2.1 性能测试的分类
- L版本上添加关机振动,定时开机振动会失效
- iOS 添加到购物车 小动画
- Vue.js学习---vue概念理解No.1
- 生成tfrecords文件(29)---《深度学习》
- 不使用vector<bool>的原因和替代方法