
public class TestT {
public static void main(String[] args) {
for (int i = 0i <10i ++) {
NumThread nt = new NumThread(1,2)
NumThread nt2 = new NumThread(2,1)
nt.start()
nt2.start()
}
}
}
class NumThread extends Thread{
private int a
private int b
public NumThread(int a,int b) {
this.a = a
this.b = b
}
public void run() {
synchronized(Integer.valueOf(a)) {
System.out.println("xxx" + Thread.currentThread().getName())
synchronized(Integer.valueOf(b)) {
System.out.println("yyy" + Thread.currentThread().getName())
}
}
}
}
这个例子首先需轿皮要先了解Integer类的机制,再进行Integer类实例化或转换时,它会缓存-128-127之间的所有对象,因此在这里我们,调用的1,2至始至终都只有两个对象。
下面就是死锁的分析:
当我们执行NumThread(1,2)时,锁的取得没问题(Integer.valueOf(a)的锁肯定没问题),接下来用NumThread(2,1),如果此时NumThread(1,2)已经取得了两个锁,这里没问题,执行完后可以继续取得锁,但如果NumThread(1,2)只取得a的锁,而此时NumThread(2,1)取得了b的锁,这时问凳帆旅题就来了。NumThread(1,2)会等待NumThread(2,1)释放b锁,而NumThread(2,1)会等等NumThread(1,2)释放a锁。
我用了一个循环启动线程是因为发生的机率不大。
可以引伸到你那个例子,用两个相同的对象作为锁。
public class TestT {
public static void main(String[] args) {
S s = new S()
S s2 = new S()
for (int i = 0i <10i ++) {
TestSleep ts = new TestSleep(s,s2)
TestSleep ts2 = new TestSleep(s2,s)
ts.start()
ts2.start()
}
}
}
class S{public int i=0}
class TestSleep extends Thread {
/**
* @param args
*/
private S s=null
private S s2 = null
public TestSleep(S s,S s2){
this.s=s
this.s2=s2
}
public void run(){
System.out.println("Now is begin Thread-A")
synchronized(s){
System.out.println("Now is begin "+Thread.currentThread().getName())
synchronized(s2) {
System.out.println(s.i)
}
}
}
}
因为java对每个对象都有一个锁,假如我们要 *** 作那对象,就得拿到那锁,你在一个类中都给2个方法加锁,那么我们在 *** 作其中一个方法时,我们就会拿到那个类的对象锁,直到 *** 作完那方法才会释放那锁,否则会一直把锁拿在手中,这样的话,其他人想 *** 作那个类,就得等待你把锁给让出来,假如我们 *** 作那个方法的时候进入了死循环,那么我碰姿们就会一直把锁捏在手里不会释放,这样就造成慧脊死锁了,别人也无法 *** 作其他笑碧绝方法欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)