volatile:
简介:
用以声明变量的值可能随时会别的线程修改
使用volatile修饰的变量会强制将修改的值立即写入主存
主存中值的更新会使缓存中的值失效
特性:
1. 可见性
当多个线程访问同一个变量时,某一个线程修改了变量的值,其他线程能够立即读取到该变量修改后的值。
2. 有序性
即程序执行时按照代码书写的先后顺序执行。
在Java内存模型中,允许编译器和处理器对指令进行重排序,
但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
3. 不具有原子性
原子性:
即事务执行不完全会发生事务回滚,恢复初始状态。
注意:
volatile不会让线程阻塞,响应速度比synchronized高,这是它的优点。
synchronized 同步锁
功能:
1. 修饰代码块:
被修饰的代码块称为同步语句块,
其作用的范围是大括号{}括起来的代码,
作用的对象是调用这个代码块的对象
一个线程访问一个对象中的synchronized(this)同步代码块时,
其他试图访问该对象的线程将被阻塞。
说明:
当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,
在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。
Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,
只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
每通过new关键字创建一个对象都是不同的对象,不能称作同一对象。
2. 修饰方:
被修饰的方法称为同步方法,
其作用的范围是整个方法,
作用的对象是调用这个方法的对象
当一个线程访问对象的一个synchronized(this)同步代码块时,
另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
说明:
countAdd是一个synchronized的,printCount是非synchronized的。
一个线程访问一个对象的synchronized代码块时,别的线程可以访问该对象的非synchronized代码块而不受阻塞。
3. 修饰静态的方法:
其作用的范围是整个静态方法,
作用的对象是这个类的所有对象
synchronized修饰方法和修饰一个代码块类似,只是作用范围不一样,
修饰代码块是大括号括起来的范围,而修饰方法范围是整个函数。
静态方法是属于类的而不属于对象的。
synchronized修饰的静态方法锁定的是这个类的所有对象。
说明:
两种写法:
1. public synchronized void method () {}
2. public void method () {
synchronized (this) {}
}
注意:
1. synchronized关键字不能继承。
2. 在定义接口方法时不能使用synchronized关键字。
3. 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步
4. 修饰类:
其作用的范围是synchronized后面括号括起来的部分,
作用主的对象是这个类的所有对象
synchronized作用于一个类T时,
是给这个类T加锁,T的所有对象用的是同一把锁。
Lock
1. 通过Lock可以知道线程有没有成功获取到锁。synchronized无法办到的。
2. Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。
Lock是一个类,通过这个类可以实现同步访问
3. synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,
而且在代码执行时出现异常,JVM会自动释放锁定,
但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
4. 在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,
但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,
lock的四个取锁方法:
lock()
就是用来获取锁。如果锁已被其他线程获取,则进行等待。
tryLock()
有返回值,表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,
也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
tryLock(long time, TimeUnit unit)
这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。
如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
lockInterruptibly()
在获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。
也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,
假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
注意:
使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,
以保证锁一定被释放,防止死锁的发生。