Java中的Volatile 和 synchronized
JAVA Memory Model
并发过程中如何处理可见性、原子性、有序性的问题
创建线程:Runnable、Thread可以简单实现多线程
1. 线程之间如何通信
a. 共享内存 - 隐式通信;
b. 消息传递 - 显示通信;wait(),notify(),notifyall()
2. 线程之间如何同步
程序中用于不同线程间操作发生的相对顺序机制
在共享内存的并发模型中,同步是显示做的;比如synchronized
在消息传递的并发模型中,由于消息的发送必须在消息接收之前,所以同步是隐式
在Java中,所有的实例域,静态变量,数组元素都存放在堆内存中,堆内存在线程之间共享的
局部变量,方法,定义参数或者异常处理,在线程之间不会共享
如何区分哪些对象是内存共享的
共享变量存储在主内存中,每个线程有自己的本地内存,存储共享变量的副本
线程A与B通信,线程A将本地内存的值更新到主内存中,线程B再将主内存的值值刷到B的本地内存中
Volatile保证可见性
1. 对于声明了Volatile的变量进行写操作的时候,JVM会向处理器发送一条Lock前缀的指令。会把这个变量所在缓存行的数据写回到主内存中
2. 在多处理器的情况下,保证各个处理器缓存一致性的特点,就会实现缓存一致性协议
synchronized:可重入锁、互斥性、可见性
Volatile:原子性、可见性;不能做到复合操作的原子性,比如i++
synchronized:会调用monitorenter、monitorexit指令
1. 获取锁的线程执行完了该代码
2. 线程执行出现异常
1. 如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,这多么影响程序执行效率。当有多个线程读写文件时,读写操作会发生冲突现象,写操作会发生冲突现象,但是读操作不会发生冲突现象。
2. 但是采用synchronized关键字来实现同步的话,就会导致一个问题:如果多个线程都只是进行读操作,当一个线程在进行读操作时,其他线程只能等待无法进行读操作。
是一个接口
Lock可以主动去释放锁,synchronized是被动
ReadWriteLock:读写锁
ReentrantLock:可重入锁;sychronized可重入锁
可重入锁:广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。ReentrantLock和synchronized都是可重入锁