概念
同步异步
消息通信机制
- 同步:发出调用之后,在没有得到结果之前,该调用不返回。调用者主动等待调用结果。
- 异步:发出调用之后,该调用直接返回,无结果。被调用者通过状态、通知进行反馈,或者通过回调函数处理这个调用。
阻塞非阻塞
调用者等待调用返回值时的状态
- 阻塞:调用结果返回之前,当前线程[ 调用者]会被挂起
- 非阻塞:不能立刻得到结果之前,调用者线程不会被阻塞
锁机制的意义
Java 允许多线程并发控制,当多个线程同时操作(增删改查)一个被共享的资源变量时,可能导致数据出现不正确的结果。加入锁保证了变量的唯一性,准确性。
Java 中的锁
公平锁、非公平锁
公平锁要求多个等待锁的线程,必须按照申请锁的顺序获得锁,而非公平锁允许抢占锁。公平锁的优点是稳定,等待锁的线程不会饿死;非公平锁的优点是性能优,因为某些线程可以避开Blocking,Runnable 之间的状态转换。
自旋锁
线程在进行状态转换(操作系统层面)过程要耗费很多时间,并且很多时候共享数据的锁定状态只会持续很短一段时间,为了节省这段很短的时间去挂起、恢复现场并不值得。如果机器上有两个以上的处理器,可以让两个线程并行执行,我们可以后面的线程“稍等片刻”,让他执行一个“自旋”。自旋等待不能代替阻塞。自旋占用处理器时间,如果等待时间长,还是要让线程阻塞。自旋只是在轻量级锁中使用,在重量级锁中,线程不能使用自旋。
锁消除
锁消除是虚拟机JIT在运行时,检测一些被同步的代码,不可能存在共享数据竞争的情况,锁将进行消除的操作。
锁粗化
锁范围扩展被称之为锁粗化。
可重入锁
可重入锁,也叫递归锁。线程A 持有一个锁,线程B 不持有锁,B 访问被这个锁保护的代码就会被阻塞,而A 则可以利用其持有的这个锁多次访问这段代码。Java 内置锁(synchronize)和Lock(ReentrantLock)都是可重入的。
类锁和对象锁
public class LockStrategy
{
public Object object1 = new Object();
// 类锁
public static synchronized void method1(){}
public void method2(){
synchronized(LockStrategy.class){}
}
// 对象锁
public synchronized void method4(){}
public void method5()
{
synchronized(this){}
}
public void method6()
{
synchronized(object1){}
}
}
例题,有一个类这样定义:
public class SynchronizedTest
{
public synchronized void method1(){}
public synchronized void method2(){}
public static synchronized void method3(){}
public static synchronized void method4(){}
}
那么,有SynchronizedTest的两个实例a和b,对于一下的几个选项有哪些能被一个以上的线程同时访问呢?
A. a.method1() vs. a.method2()
B. a.method1() vs. b.method1() // a,b,对象锁
C. a.method3() vs. b.method4()
D. a.method3() vs. b.method3()
E. a.method1() vs. a.method3() //对象锁,类锁
答案是什么呢?BE
偏向锁、轻量级锁和重量级锁
Java 对象内存布局中,对象头的Mark Word:
整个 synchronized 锁流程如下:
- 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁(偏向于第一个获得它的线程)
- 如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1
- 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
- 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁
- 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
- 如果自旋成功则依然处于轻量级状态。
- 如果自旋失败,则升级为重量级锁
悲观锁、乐观锁
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
乐观锁:假定不会发生并发冲突,只在提交操作时检测是否违反数据完整性。(使用版本号或者时间戳来配合实现)
共享锁,排它锁
共享锁:读操作。事务A 对Data 加锁之后,事务B 依然可以对Data 加共享锁(排它锁不可以),读操作。
排它锁:读、修改操作。事务A 对Data 加锁之后,事务B 不可以对Data 加任何锁。
读写锁
资源能够被多个读线程访问,或者,只被一个写线程访问(不能存在读线程)。Java当中的读写锁通过ReentrantReadWriteLock实现。
互斥锁
所谓互斥锁就是指一次最多只能有一个线程持有的锁。synchronized和Lock就是互斥锁。
线程同步的方式有哪些?
- 同步方法:synchronized 关键字修饰的方法
- 同步代码块:synchronized 关键字修饰的语句块
- 使用特殊域变量(volatile)实现线程同步
- 使用reentrantLock 实现线程同步
- 使用局部变量实现线程同步:如果使用ThreadLocal 管理变量,则每一个使用该变量的线程都获得一个该变量的副本,副本之间相互独立,这样每个线程都可以修改自己的变量副本,而不会对其他线程产生影响。
标签:同步,Java,synchronized,void,线程,自旋,public From: https://blog.51cto.com/u_11290086/5804045