lock ,sychronized,volatile的区别
p34 p77 p124 (内推军书)
https://blog.csdn.net/weixin_41563161/article/details/102458297重量级锁、自旋锁、轻量级锁、偏向锁、悲观、乐观锁等各种锁
https://blog.csdn.net/weixin_41563161/article/details/104117425 synchronized原理以及锁优化
1 java的线程抽象内存模型
java的线程抽象内存模型中定义了每个线程都有一份自己的私有内存,里面存放自己私有的数据,其他线程不能直接访问,而一些共享数据则存在主内存中,供所有线程进行访问。
上图中,如果线程A和线程B要进行通信,就要经过主内存,比如线程B要获取线程A修改后的共享变量的值,要经过下面两步:
(1)、线程A修改自己的共享变量副本,并刷新到了主内存中。
(2)、线程B读取主内存中被A更新过的共享变量的值,同步到自己的共享变量副本中。
2 java多线程中的原子性、可见性、有序性
(1)、原子性:是指线程的多个操作是一个整体,不能被分割,要么就不执行,要么就全部执行完,中间不能被打断。
(2)、可见性:是指线程之间的可见性,就是一个线程修改后的结果,其他的线程能够立马知道。
(3)、有序性:为了提高执行效率,java中的编译器和处理器可以对指令进行重新排序,重新排序会影响多线程并发的正确性,有序性就是要保证不进行重新排序(保证线程操作的执行顺序)。
volatile关键字的作用
volatile关键字的作用就是保证了可见性和有序性(不保证原子性)。
Volatile如何保证内存可见性:
1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。
Volatile如何保证内存有序性:
volatile能禁止指令重排,在指令重排序优化时,在volatile变量之前的指令不能在volatile之后执行,在volatile之后的指令也不能在volatile之前执行,所以它保证了有序性。
synchronized关键字的作用
synchronized提供了同步锁的概念,被synchronized修饰的代码段可以防止被多个线程同时执行,必须一个线程把synchronized修饰的代码段都执行完毕了,其他的线程才能开始执行这段代码。
因为synchronized保证了在同一时刻,只能有一个线程执行同步代码块,所以执行同步代码块的时候相当于是单线程操作了,那么线程的可见性、原子性、有序性(线程之间的执行顺序)它都能保证了。
3 synchronized和volatile区别
synochronizd和volatile关键字区别:
1. volatile关键字解决的是变量在多个线程之间的可见性;而sychronized关键字解决的是多个线程之间访问共享资源的同步性。
2. volatile只能用于修饰变量,而synchronized可以修饰方法,以及代码块。(volatile是线程同步的轻量级实现,所以volatile性能比synchronized要好,并且随着JDK新版本的发布,sychronized关键字在执行上得到很大的提升,在开发中使用synchronized关键字的比率还是比较大)
3. 多线程访问volatile不会发生阻塞,而sychronized会出现阻塞。
4. volatile能保证变量在多个线程之间的可见性,但不能保证原子性;而sychronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公有内存中的数据做同步。
4synchronized与lock区别
1、lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现。
2、synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而lock在发生异常时,如果没有主动通过unlock()去释放锁,则很可能造成死锁现象,因此使用lock时需要在finally块中释放锁。
3、lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能响应中断。
4、通过lock可以知道有没有成功获取锁,而synchronized却无法办到。
5、lock可以提高多个线程进行读操作的效率(读写锁)。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
5 synchronized
synchronized 是Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。
6.volatile
深入剖析volatile关键字
volatile是一个轻量级的同步机制。用来修饰共享可变变量,对volatile变量的读写操作都是从高速缓存或者主内存中读取。
volatile的作用
volatile关键字被称为轻量级锁,能保证可见性和有序性。不同的是原子性方面仅能保证写volatile变量操作的原子性,但没有锁的排他性。而且不会引起上下文的切换。
保证可见性(强制刷新在主存,其他线程缓存无效)和有序性(禁止指令重排序),这些都是上面的用内存屏障完成的.
volatile
是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
对于用volatile修饰的变量,JVM虚拟机只是保证从主内存加载到线程工作内存的值是最新的。
一句话说明volatile的作用:实现变量在多个线程之间的可见性。
7Lock
synchronized
是Java语言的关键字,是内置特性,而ReentrantLock
是一个类(实现Lock
接口的类),通过该类可以实现线程的同步。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;
void unlock();
Condition newCondition();
}
Lock一般的使用如下:
Lock lock= ...;//获取锁
lock.lock();
try{
//处理任务
}catch(Exception e){
}finally{
lock.unlock();//释放锁
}
lock()
、tryLock()
、tryLock(long time, TimeUnit unit)
和lockInterruptibly()
是用来获取锁的,unLock()
方法是用来释放锁的,其放在finally块里执行,可以保证锁一定被释放,newCondition
方法下面会做介绍(通过该方法可以生成一个Condition对象,而Condition是一个多线程间协调通信的工具类)。
8synchronized, lock和volatile区别(可见性、原子性、有序性)