线程会出现的问题:同步 与 互斥
什么是同步? 什么是互斥?
Synchronized 可以作用于哪里?实现的原理?性能优化有什么?
1.首先来说说什么是同步与互斥?
同步:线程间的通信(线程合作)
互斥:多线程并发时,某一时刻只能有一个线程访问共享资源
2.Synchronized同步处理可以作用于哪里:(1)同步方法 (2)同步代码块
(1)同步代码块: 锁的对象是 (this/ object及其子类 类对象 / 当前类.class)
Synchronized(锁的对象){
//此处为代码在任意一个时刻只能有一个线程进去
}
代码如下:
class sellTicket implements Runnable{
private int ticket = 20000;
@Override
public void run() {
while(ticket >0 ){
synchronized (this){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还剩下"+ticket--+"票");
}
}
}
}
public class SynchronizedTest {
public static void main(String[] args) {
Runnable runnable = new sellTicket();
Thread thread1 = new Thread(runnable,"黄牛A");
Thread thread2 = new Thread(runnable,"黄牛B");
thread1.start();
thread2.start();
}
}
(2)同步方法:直接在方法声明上使用synchronized,此时表明同步方法在任意时刻只能有一个线程进入 (默认锁的是this)
Synchronized修饰普通方法 , 锁当前对象this
Synchronized修饰类的静态方法 , 锁当前类.class
代码如下:
class sellTicket implements Runnable{
private int ticket = 20000;
@Override
public void run() {
while(ticket >0 ) {
sell();
}
}
public synchronized void sell(){
System.out.println(Thread.currentThread().getName()+"还剩下"+ticket--+"票");
}
}
public class SynchronizedTest {
public static void main(String[] args) {
Runnable runnable = new sellTicket();
Thread thread1 = new Thread(runnable,"黄牛A");
Thread thread2 = new Thread(runnable,"黄牛B");
thread1.start();
thread2.start();
}
}
3.Synchronized实现原理
底层实现:在使用synchronized时必须保证锁定的对象必须为object以及其子类对象
synchronized使用的是JVM层级别的MonitorEnter与MonitorExit实现
这两个指令都必须获取对象的同步监视器Monitor
4.synchronized优化
优化让每个线程通过同步代码块时速度提高,之前synchronized获取锁失败,将线程挂起——悲观锁
优化1:CAS
什么是CAS? Compare And Swap(无锁操作)是一种乐观锁
CAS中有三个参数 (O,V,N)
O:当前线程存储的变量值 V:内存中该变量的具体值 N:希望修改的变量值
(1)当O == V时,此时表示还没有线程修改共享变量的值,此时可以成功将内存中的值改为N
(2)当O != V时,此时表示内存中共享变量值已被其他线程修改,此时返回内存中的最新V,再次尝试修改变量
注意:CAS产生的问题
1.ABA问题 :比如旧值A改为了B再改为了A,刚好在做CAS检查发现旧值并没有变化,实际已经改变
解决方法:添加一个版本号
2.自旋会产生大量的处理器资源
自旋:失败重试
解决方式:JVM尝试自旋一段时间后,若在此时间内,线程成功获取到锁,再下次获取锁时,适当延长时间,反之,适当所短时间
3.公平性
处于阻塞态线程可能会一直无法获取到锁 , LOCK锁可以实现公平性,Synchronized无法实现公平性
优化2:锁的升级 JDK1.6后默认偏向锁
无锁 —>偏向锁 —>轻量级锁 —> 重量级锁
偏向锁:进去同步方法或同步代码块始终是一个线程
轻量级锁:不同时刻有不同线程尝试获取锁
重量级锁:同一时刻请求同一把锁,有竞争
注意:锁只有升级过程没有降级过程
其他优化: 锁的粗化与锁消除
锁粗化:当出现多次连续的加锁与解锁过程,会将多次加锁减锁过程粗化为一次的加锁与解锁过程
锁消除:当对象不属于共享资源时,对象内部的同步方法或同步代码块的锁会被自动解除