门户网站静态页面,网站用户体验是什么,优秀网站页面设计图片,商品推广软文范例100字引言
死锁状态的大致情况是#xff1a;Thread_1在获得A对象的锁后#xff0c;紧接着去请求B对象的锁 #xff0c;Thread_2在获得了B对象的锁后#xff0c;紧接着又去请求A对象的锁#xff0c;如下图#xff1a; 一、模拟一个死锁
public class DeadLockDemo {static cl…引言
死锁状态的大致情况是Thread_1在获得A对象的锁后紧接着去请求B对象的锁 Thread_2在获得了B对象的锁后紧接着又去请求A对象的锁如下图 一、模拟一个死锁
public class DeadLockDemo {static class A {public synchronized void saying() {System.out.println(Thread.currentThread().getName() A start...........);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}new B().saying();System.out.println(Thread.currentThread().getName() A end.............);}}static class B {public synchronized void saying() {System.out.println(Thread.currentThread().getName() B start...........);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}new A().saying();System.out.println(Thread.currentThread().getName() B end.............);}}public static void main(String[] args) {new Thread(() - new A().saying(), t1).start();new Thread(() - new B().saying(), t2).start();}
}
可以看到在线程 t1 调用A对象的saying互斥方法的时候t1拿到了A对象的锁而如果想完成saying方法必须去请求B对象的锁才可以执行到B对象的saying互斥方法。线程 t2调用B对象的saying互斥方法的时候t2拿到了B对象的锁而如果想完成saying方法必须去请求A对象的锁才可以执行到A对象的saying互斥方法。
这就导致了死锁的出现程序会陷入无休止的“死循环”中。
如果没有2秒的睡眠时间程序会很快因内存溢出而瘫痪 否则程序会不停的循环下去直到崩溃。 二、synchronized 锁的错误用法
使用synchronized 并不简单以下这些用法一定要在实际开发中注意避免。
2.1 synchronized 锁定字符串对象
synchronized 可以给对象加锁但这些对象不应该包括 String、Integer 这类共享对象。说String、Integer是共享对象是因为在某些情况下Java会共享一些数据来提高性能和节约内存。
例如一个字符串 Hello如果以此对象为锁定目标那么就可能在非常不恰当的位置造成线程阻塞或死锁
public class T {String s1 Hello;String s2 Hello;void m1() {synchronized (s1) {}}void m2() {synchronized (s2) {}}
}
如上代码所示s1 和 s2 虽然声明了两个变量但实际上Hello 字符串是共享的因此锁也是一份如果你不希望造成莫名其妙的线程阻塞一定要记得synchronized 不要加在 String、Integer 这类对象上。
2.2 锁对象的引用被重新赋值
理解这个问题需要清楚synchronized加锁的目标对象是什么究竟是栈内存中的引用还是堆内存中的对象数据
我们保证同步的目的是有序的执行堆中的数据所以很明显synchronized 锁定的应该是堆内存中实际的对象而不是栈中的引用。
那么如果引用被重新赋值那么整个并发程序可能造成更加难以排查的问题
public class T_ChangeLock {private Object lock new Object();public void doSync() {synchronized (lock) {while (true) {try {TimeUnit.SECONDS.sleep(1);// 打印当前线程System.out.println(Thread.currentThread().getName());} catch (InterruptedException e) {}}}}public static void main(String[] args) throws InterruptedException {T_ChangeLock t new T_ChangeLock();new Thread(() - t.doSync(), t1).start();// 启动第一个线程TimeUnit.SECONDS.sleep(1);// 锁对象改变t.lock new Object();// 想一想t2 是否可以被成功阻塞new Thread(() - t.doSync(), t2).start();}
}
doSync 是个同步方法方法内死循环输出当前线程IDt1首先抢到 doSync 的执行权即抢到 lock 锁对象不出意外的话其他线程都将无法执行 doSync 方法然而在执行了 lock new Object() 方法后奇怪的事情发生了 所以为了不让你的同步逻辑失效请谨慎处理锁对象的引用。