知识总结:
- synchronized 支持锁重入
- 方法锁 == synchronized(this)
- 静态方法static上面加锁 == synchronized(T.Class)
- 锁方法如果发生异常,会释放锁,等待队列里面的线程会抢到锁,导致数据异常
public class Thread_03_synchronize implements Runnable{
private Integer count = 100;
@Override
public synchronized void run() {
count--;
System.out.println(Thread.currentThread().getName()+"____"+count);
}
private synchronized void method1(){
System.out.println("进入方法1了");
try{
Thread.sleep(1000);
}catch (Exception e){
}
System.out.println("开始进入方法2了");
method2();
System.out.println("方法二结束了");
}
private synchronized void method2(){
System.out.println("哈哈哈哈");
}
/**
* 原理解释:
* 线程1 拿着t对象的锁,执行方法1 方法2
* 线程2 执行的时候 等线程1 完成后执行
* @param args
*/
public static void main(String[] args) {
//一直减减减();
锁重入问题();
}
private static void 锁重入问题() {
System.err.println("开始了");
Thread_03_synchronize t = new Thread_03_synchronize();
Thread_03_synchronize t2 = new Thread_03_synchronize();
new Thread(()->{
t.method1();
}).start();
System.err.println("调用方法二");
new Thread(()->{
t2.method2(); //t1.method2
}).start();
System.err.println("结束了");
}
private static void 一直减减减() {
Thread_03_synchronize t = new Thread_03_synchronize();
for (int i = 0; i < 100; i++) {
new Thread(t,"haha").start();
}
}
}
打开偏向锁,new出来的对象,默认就是一个可偏向匿名对象
偏向锁在项目一启动的时候没有开启,有一个开启时间(默认四秒)
锁升级的理解:
- synchronize(Object) 实现其实是在object这个对象的markworld上放一个线程ID
a. 对象的组成:
ⅰ. markworld
ⅱ. 指针
ⅲ. 对象属性值
ⅳ. 忘记了 - 最开始一个线程的时候是加的偏向锁
- 当有线程竞争的时候,锁升级为自旋锁
a. 一个线程在执行
b. 其他线程在cpu中自旋(while循环)
c. 存在于用户态 - 当自旋锁中,一个线程自旋10次以上,锁升级为重量级锁
a. 重量级锁需要通过操作系统(OS)
b. 一个线程在执行,其他线程在队列中等待,不占用cpu
c. 存在于内核态中 - 锁不能降级
- 当线程数量少,运行时间短–自旋锁比较好
- 当线程数量多,运行时间长 – 重量级锁比较好