- synchronized 关键字
锁的是对象。 synchronized 锁this 和 锁方法,都是锁当前运行对象。
- 静态同步方法:
锁的是当前类型的类对象 ,Test.class
-
锁的重入性: 同一个线程,多次访问同步代码块,(锁定的是同一个对象),是可以重入的。
-
当同步方法中发生异常时,会自动释放锁资源,不会影响其他线程的执行。
-
volatile 关键字: 内存可见,线程中对某个变量的操作只能是改变内存中的值,cpu做计算时,只会从高速缓存中读取数据。 加上volatile 关键字,会通知os操作系统底层,在cpu 计算时,要检查内存数据的有限性。就会依据内存中的数据来刷新缓存,保证最新的内存数据被使用。
-
volatile 关键字只能保证可见性,不能保证原子性。不是加锁问题,只是内存数据可见。
-
join关键字: 阻塞当前线程,直到调用join的线程运行结束。
-
Atomic 原子操作类型,保证每个方法都是原子操作。可以保证线程安全。
-
synchronized 关键字 在使用时,尽量避免同步方法, 使用同步代码块。
synchronized(this){
}
- CountDownLatch: 在开放前等待,开放后执行。 可以避免锁效率低下的问题
final CountDownLatch latch = new CountDownLatch(1);
latch.await(); // 等待门闩的开放。 不是进入等待队列
latch.countDown(); // 门闩-1
-
RenentrantLock: 重入锁,效率比synchronized高,量级较轻。使用重入锁必须手动释放锁标记。一般定义在finally 代码块中。
1> Lock lock=new ReentrantLock();
lock.lock(); // 加锁
要锁住的代码块
lock.unlock(); //释放锁2> 尝试锁,未获得锁标记前,如果没有限制时间,会一直处于阻塞状态
void m2(){
boolean isLocked = false;
//获取尝试锁,此时如果没有获取到,会处于阻塞状态。
// lock.tryLock();
//在指定的时间内获取尝试锁
isLocked = lock.tryLock(5, TimeUnit.SECONDS);
if(isLocked){
System.out.println("method is synchronized")
}else{
System.out.println("method is unsynchronized")
}
//释放锁, 尝试锁在解除锁标记时一定要先判断是否获取了锁标记。
if(isLocked){
lock.unlock();
}
}
3> 可打断,阻塞等待锁, 可以被其他线程打断阻塞状态,打断后抛出异常
lock.lockInterruptibly(); // 尝试获取可中断锁,没获取到前处于阻塞状态
lock.unlock(); 释放锁
4> 公平锁, 等待时间越长的线程,先获取到锁。
private static ReentrantLock lock = new ReentrantLock(true);
锁的分类
偏向锁, 自旋锁,轻量级锁,重量级锁。
锁的使用: 先提供的是偏向锁,如果不满足,升级为轻量级锁,再不满足,升级为重量级锁。 自旋锁是 一个过渡的锁状态,不是一种实际的锁类型。
偏向锁: 是一种解释性锁。如果代码中不可能出现多线程争抢同一个锁。Jvm编译代码,解释执行的时候会消除synchronized 的同步代码结果。使用锁标记来记录锁状态。
轻量级锁: 有多线程并发访问,先提升为轻量级锁
自旋锁: 当获取锁的时候,并未获取到,为了提高效率,JVM自动执行若干空循环,再次申请锁,而不是直接进入阻塞状态。