Java多线程中的死锁问题

1、什么是死锁

我们假设有两个线程A和B,两者的run,都要去访问两个对象,A要访问X和Y,B要访问X和Y,这个时候,A会给X和Y加上自己的互斥锁,而B也会给X和Y加上互斥锁,A要首先给X加上锁,然后再去争取锁住Y,而这时,B一看X被锁了,就率先锁住了Y,这个时候,A在等着B释放Y,B在等着A释放X,两者就相当于死锁了,谁都需要对方退一步,相同的是谁也不会退一步。

看一段代码来实现上述情况:

public class TestThread01 implements Runnable{
public int flag =1;
static Object x =new Object();
static Object y =new Object();
public void run(){
    System.out.println("flag="+flag);
    if(flag==1){
        synchronized (x) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
            synchronized (y) {
                System.out.println("1");
            }
        }
    }
    if(flag==0){
        synchronized (y) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
            synchronized (x) {
                System.out.println("2");
            }
        }
    }
}
public static void main(String[] args) {
    TestThread01 t1 = new TestThread01();
    TestThread01 t2 = new TestThread01();
    t1.flag=1;
    t2.flag=0;
    Thread t11 = new Thread(t1);
    Thread t22 = new Thread(t2);

    t11.start();
    t22.start();
}
}

上述代码其实就是一个很好的死锁的例子,t11和tt2两个线程,都会去执行run方法,一个去执行flag为1的情况,一个去执行flag为2的情况,而这两个情况里,会产生之前所述的死锁。
运行结果也就是只会输出flag=1和flag=2两句话,之后就会死住。

2、一道死锁相关的面试题

public class TestThread01 implements Runnable{
int b =100;
public synchronized void m1(){
    b=1000;
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {

        e.printStackTrace();
    }
    System.out.println("b = "+b);
}
public void m2(){
    System.out.println(b);
}
public void run(){
    m1();
}
public static void main(String[] args) {
    TestThread01 t1 = new TestThread01();
    Thread t11 = new Thread(t1);
    t11.start();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    t1.m2();
}
}

请问如上代码的输出结果:
m1方法被锁定了,请问t1的m2方法输出的结果是初始化的100,还是修改后的1000?
答案是1000,虽然m1被锁定了,t11线程在调用m1之后将b改为1000,然后休眠5秒,但是t1对象访问的并不是锁定的m1,而是m2,m2输出当前内存中的b的值,所以,我们要记住,被锁定的方法不能被访问,但是其余的变量和方法,我们是可以访问的。

我们将上面的代码修改一下,如下:

 public class TestThread01 implements Runnable{
int b =100;
public synchronized void m1(){
    b=1000;
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {

        e.printStackTrace();
    }
    System.out.println("b = "+b);
}
public void m2(){
    Thread.sleep(2500);
    b = 2000;
}
public void run(){
    m1();
}
public static void main(String[] args) {
    TestThread01 t1 = new TestThread01();
    Thread t11 = new Thread(t1);
    t11.start();
    t1.m2();
}
}

这段代码我们将m2也设置成了修改b为2000,那么m1修改b为1000,最后结果是多少呢?
分析一下:开了一个线程t11,t11调用run,run调用m1,修改b为1000后,休眠5秒,这个时候,我们调用了m2,修改b为2000,输出结果也是2000,这也说明了,我们锁定了m1方法,但是依旧能去修改b,所以这也就告诉我们,我们要把访问涉及到同个资源的方法,都要去加锁。
例如:我们将m2修改为加上锁的m2,那么再去运行,b就是1000,因为线程在执行m1,m1被锁,因为涉及到了b,所以m2无法去锁定,也就没法去执行。
但是,我们在main方法里去输出一下:System.out.print(t1.b);这个时候,等待m1释放对b的锁之后,m2就可以执行了,所以输出为2000.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值