[toc]
前面我们介绍了在Java中可以用加锁关键字synchronized
保证原子性。
在线程安全中通过synchronized
给线程加锁,是线程由并行变为串行,这时可能会有疑问说:使用多线程的目的就是提高代码效率,加锁后就变成了单线程了,岂不是多此一举了?
因此在使用多线程时要注意一下几点
这里我们以 :使用多线程实现count自增 为例
java 代码解读复制代码class Counter{
public int count =0;
public synchronized void increase(){
count++;
}
}
java 代码解读复制代码class Counter{
public int count =0;
public void increase(){
System.out.println("加锁之前的操作...");
//锁对象 需提供一个对象
synchronized (this){
count++;
}
System.out.println("加锁之后的操作...");
}
}
使用
synchronized
修饰的代码块涉及的指令,并不是在CPU上无脑的执行完,而是有可能执行了一半就被调度走了,但是即便被调度出CPU也不会释放锁,别的线程尝试获取锁时依然会阻塞等待
java 代码解读复制代码class Counter {
public static int count = 0;
public synchronized static void increase() {
count++;
}
}
举栗:
java 代码解读复制代码class Counter{
public int count =0;
/**
* 执行自增
*/
public synchronized void increase(){
count++;
}
/**
* 不加锁
*/
public void increase1(){
count++;
}
}
在1.2中**()里面的this指的是:是对那个对象进行加锁** 加锁操作,是针对 一个对象进行的。 而我们需要的理解的是:
synchronized
锁的是什么,当两个线程竞争的是同一个锁时,才会产生线程安全(两个线程竞争不同的锁时,根本不会产生任何的线程安全,两把锁之间没有任何关系,不会产生阻塞等待)。
因此在判断是否会产生锁竞争时,只需判断一下锁对象是否是同一个对象。
在Java虚拟机中,对象在内存结中的结构可以划分为4个区域:
synchronized的几种用法
互斥 一个线程获取了锁之后,其他线程就必须阻塞等待,等到当前获取锁的线程释放了锁之后再去竞争
内存可见(刷新内存)
synchronized
实现内存可见的机制是通过原子性完成的,一个线程完成了读、改、写回内存这一操作之后,再释放锁,下一个线程才能获取锁,再开始读取 所以保证了下一个线程读到的值是上一个线程写回主内存的最新值可重入 在方法调用的链路中,可能存在多个被
synchronized
修饰的方法或者代码块 对于同一对象,针对同一个线程(当前获得锁的线程)互斥那么这个锁就不可以重入,会产生一个互斥等待的现象,也叫死锁 对于同一锁对象,针对同一个线程(当前获得锁的线程)不互斥那么这个锁就可以重入
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。