2 yan huaxiangmo YAN_HUAXIANGMO 于 2017.09.09 04:06 提问

想自己编写一个线程死锁产生的例子,加深对synchronize的理解,但是发现了这个,理解不了

我的思路:
在一个类中弄两个个方法,一个A,B都加锁,要想A要得到B,B也想得到A,这样就能产生死锁。因为是同一个类,所以为了能使线程调用方法A和方法B,需要在run方法中对两个方法都调用一次,单一 一个线程按照顺序调用A、B方法就会陷入死循环,所以我用了一下方式,但还是陷入了死循环,谁能解释一下,我能得到的结论就是synchronized修饰的方法是把整个类中所有带有synchronized修饰方法都上锁了,是不是啊?

 public class SynchronizedLocked_Dead implements Runnable {
    private static int num = 0 ;
    public synchronized void get1(){
            System.out.println(Thread.currentThread().getName()+",调用1");
            //准备创建两个线程,让线程1跳过getP()方法,然后线程2进来直接进入getP()方法
            num++;
            if(num>1){
                getP();
            }
    }
    public synchronized void getP(){
        System.out.println(Thread.currentThread().getName()+"这是P:");
        //为了让线程1执行完get1方法后,睡着,好让线程2能够顺利抢占到get1方法,
        //并且等待线程1释放getP()方法
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程1睡醒就想运行get1方法,但是此时线程2应该还在get1方法中等待getP方法释放
        //此时线程1又想获取线程2中的getP方法,所有陷入死锁
        get1();
    }


    @Override
    public void run() {
        System.out.println("");
        System.out.println(Thread.currentThread().getName()+"进来了");
        System.out.println("");

        get1();
        getP();
    }
    public static void main(String[] args) {
        SynchronizedLocked_Dead me = new SynchronizedLocked_Dead();
        new Thread(me,"t1").start();
        new Thread(me,"t2").start();
    }

}

运行结果:
t1进来了

t1,调用1
t1这是P:
t2进来了//就这一下下就没了?

t1,调用1
t1这是P:
t1,调用1
t1这是P:
t1,调用1
t1这是P:
t1,调用1
t1这是P:
......................死循环

4个回答

zhanghe__
zhanghe__   2017.09.09 11:02
已采纳

首先说明一下,这个synchronised关键字在不加static修饰符的情况下,锁的是当前对象而非类, 显然你的用例中锁的是对象。然后你两个线程开始
跑呀跑,运气好的就像你用例中的t1取到了锁,锁住了当前对象,然后在两个方法中循环,当前对象一直被锁着,t2线程拿不到当前对象,一直在等。
就造成你现在看到 的样子。

zhanghe__
zhanghe__ 回复YAN_HUAXIANGMO: 比如说你写一个Synchronized.class; 这个就是类; Object s1 = new Synchronized();s1就是实例,是对象。 你问过加不加static区别,加了static就是静态,可以被类直接调用,不加static为成员,不能被类直接调用,但是能被实例调用。
2 个月之前 回复
YAN_HUAXIANGMO
YAN_HUAXIANGMO 回复事在人为丶: 感谢,懂了,那加了static就锁住类,什么都不能访问了,包括普通方法,对吗
2 个月之前 回复
zhanghe__
zhanghe__ 回复YAN_HUAXIANGMO: 对象是实例,new出来的。 类是class。 你new 两个试试,就不会阻塞了。如果你要写死锁,尝试去锁同一个资源,比如new 两个object
2 个月之前 回复
YAN_HUAXIANGMO
YAN_HUAXIANGMO “锁的是当前对象而非类”,这里当前对象不就是当前类吗,而且这个例子加不加static结果都一样的,如果锁住的是当前类我就能理解这个例子了,也就是说在同一个类下,synchronize修饰get1,getP方法,那么只要其中一个方法被线程调用,另一个也不能够被其他线程访问,这样理解行不行
2 个月之前 回复
hongyu83916
hongyu83916   2017.09.09 09:33

你加锁的是 get1(); getP();两个方法;在run方法中,代码在get1()之前是不受控的,t1或t2谁想抢到执行get1()就再也没释放锁,所以第二个线程,
永远进不来。sleep方法是不释放锁的, 除非加锁的get1()或getP()执行完。

YAN_HUAXIANGMO
YAN_HUAXIANGMO 但是我这个,是先进来的线程用完get1后调用了getP,这时候后面的线程应该去调用get1,但是并没有,我能得到的结论就是synchronized修饰的方法(例如get1)是把整个类中所有带有synchronized修饰方法(get1、getP)都上锁了,对不
2 个月之前 回复
qq_35928356
qq_35928356   2017.09.09 09:46

synchronized 锁的是对象 ,当一个线程进入 该对象内的某个synchronized修饰的方法 时,先获得该对象的锁,之后 ,其他线程试图进入该对象的任何synchronized修饰的方法时,都会阻塞。
但可以调用非 synchronized 的方法。

YAN_HUAXIANGMO
YAN_HUAXIANGMO 回复YAN_HUAXIANGMO: 想理解透彻点
2 个月之前 回复
YAN_HUAXIANGMO
YAN_HUAXIANGMO 所以这个例子锁的对象就是当前类对吧,但是加static修饰也是获得当前类,在方法上加static和不加的区别体现在哪?带参数锁的是传入的参数对象吗?先理解透彻点
2 个月之前 回复
YAN_HUAXIANGMO
YAN_HUAXIANGMO   2017.09.09 14:20

谢谢楼上几位的回答,我改成这样了

 class C{
    public synchronized void getD(D d){
        System.out.println("我想拿到D,我才结束");
        d.getD();
    }
    public synchronized void getC(){
        System.out.println("拿到C,我结束了");
    }
}
class D{
    public synchronized void getC(C c){
        System.out.println("我想拿到C,我才结束");
        c.getC();
    }
    public synchronized void getD(){
        System.out.println("拿到D,我结束了");
    }
}
public class SynchronizedDeadLock implements Runnable{
    public static C c = new C();
    public static D d = new D();
    @Override
    public void run() {
        c.getD(d);
    }
    public static void main(String[] args) {
        new Thread(new SynchronizedDeadLock()).start();
        d.getC(c);
    }
}
Csdn user default icon
上传中...
上传图片
插入图片