黑马程序员技术交流社区

标题: 多线程锁的问题 [打印本页]

作者: 乔青山    时间: 2014-3-2 10:05
标题: 多线程锁的问题
本帖最后由 乔青山 于 2014-3-2 14:48 编辑

class Ticket implements Runnable

{
            private int tick = 100;
            Object obj = new Object();
            boolean flag = true;

            public void run(){
                        if(flag){
                                    while(true){
                                                synchronized(obj){            //obj锁
                                                            show();
                                                }
                                    }
                        }else{
                                    while(true)
                                                show();
                        }
            }

            public synchronized void show(){    //this锁
                        synchronized(obj){                       //obj锁
                                    if(tick>0){
                                                try{
                                                            Thread.sleep(10);
                                                }catch(Exception e){
                        
                                            }
                                            System.out.println(Thread.currentThread().getName()+"code.........:"+tick--);
                                    }
                        }
            }
}

class DeadLockDemo
{
            public static void main(String[] args){
                        Ticket t = new Ticket();
               
                        Thread t1 = new Thread(t);        
                        Thread t2 = new Thread(t);        
                        t1.start();
                        try{Thread.sleep(10);}catch(Exception e){}
                        t.flag = false;                                
                        t2.start();
            }
}

我想问一下,什么情况下是this锁,函数上的锁就一定是this锁是么?代码块的锁呢?
另外上面的程序会出现死锁,为什么?t1和t2都在调用show(),那t1执行show的时候t2应该执行不了啊,锁应该锁上了啊,怎么会出现死锁呢?
本人菜鸟,线程同步这个地方学的很吃力,锁有点完全不理解了,希望讲解的能详细一点

作者: 李白衣    时间: 2014-3-2 12:11
本帖最后由 李白衣 于 2014-3-2 12:12 编辑

线程0在flag为true时进入循环,获得锁的过程就是:obj-->this-->obj,obj和obj是同一个锁,所以线程0想要执行下去,就要先获得obj锁,然后获得this锁。
线程1在flag为false的时候进入循环,获得锁的过程是:this-->obj,所以线程1想要执行下去,就要先获得this锁,然后获得obj锁。
这里假设,线程0在获得obj锁后,还没有执行下一句,CPU就切换了,所以线程0拿到了obj的锁。
轮到线程1执行,线程1执行首先就要拿到this锁,this没有被锁定,所以可以继续执行,然后在线程1执行下一句的时候,需要拿到obj的锁,但是obj已经被线程0锁定,无法继续执行下去了。
CPU只有切换到线程0,让线程0来继续执行,但是此时线程0执行下一句就要用到this锁,this锁被线程1锁定了。线程0也无法执行了,这样就成了死锁。更详细的解释:
//代码一
class Deadlocker {
int field_1;
private Object lock_1 = new int[1];
int field_2;
private Object lock_2 = new int[1];

public void method1(int value) {
  “synchronized” (lock_1) {
   “synchronized” (lock_2) {
    field_1 = 0; field_2 = 0;
   }
  }
}

public void method2(int value) {
  “synchronized” (lock_2) {
   “synchronized” (lock_1) {
    field_1 = 0; field_2 = 0;
   }
  }
}
}

参考代码一,考虑下面的过程:

  ◆ 一个线程(ThreadA)调用method1()。

  ◆ ThreadA在lock_1上同步,但允许被抢先执行。

  ◆ 另一个线程(ThreadB)开始执行。

  ◆ ThreadB调用method2()。

  ◆ ThreadB获得lock_2,继续执行,企图获得lock_1。但ThreadB不能获得lock_1,因为ThreadA占有lock_1。

  ◆ 现在,ThreadB阻塞,因为它在等待ThreadA释放lock_1。

  ◆ 现在轮到ThreadA继续执行。ThreadA试图获得lock_2,但不能成功,因为lock_2已经被ThreadB占有了。

  ◆ ThreadA和ThreadB都被阻塞,程序死锁。

PS:如果在同步代码快里面又写一个同步代码快,很容易变成死锁。
函数上的就是this锁,代码里面this锁就是你new的ticket对象。

作者: 陪你等日出    时间: 2014-3-2 13:10
同步函数的锁是this锁,函数上的锁不一定是this锁,静态同步函数的锁是类的字节码.class,再说程序为什么会出现死锁:
  1. class Ticket implements Runnable

  2. {
  3.         private int tick = 10000;
  4.         Object obj = new Object();
  5.         boolean flag = true;

  6.         public void run(){
  7.                 if(flag){
  8.                         while(true){
  9.                                 //现在0线程要获取obj锁
  10.                                 synchronized(obj){//obj锁  
  11.                                         //现在拥有obj锁的0线程要运行同步方法show(),需要获取this锁
  12.                                         show();
  13.                                         //运行完同步代码后释放锁
  14.                                 }
  15.                         }
  16.                 }else{
  17.                         //现在flag==false,然后1线程开启,执行下面代码,
  18.                         while(true){
  19.                                 //1线程获取了this锁,现在需要获取obj锁  
  20.                                 show();
  21.                                 // 这时0线程拥有obj锁想要获取this锁,1线程拥有了this锁想获取obj锁,两线程都不释放锁,死锁产生
  22.                         }
  23.                 }
  24.         }

  25.         public synchronized void show(){//this锁
  26.                 synchronized(obj){//obj锁
  27.                         if(tick>0){
  28.                                         try{
  29.                                                 Thread.sleep(1);
  30.                                         }catch(Exception e){

  31.                                 }
  32.                                 System.out.println(Thread.currentThread().getName()+"code.........:"+tick--);
  33.                         }
  34.                 }
  35.         }
  36. }

  37. class DeadLockDemo
  38. {
  39.         public static void main(String[] args){
  40.                 Ticket t = new Ticket();

  41.                 Thread t1 = new Thread(t);        
  42.                 Thread t2 = new Thread(t);        
  43.                 t1.start();
  44.                 try{Thread.sleep(10);}catch(Exception e){}
  45.                 t.flag = false;
  46.                 //现在0线程正在执行,刚刚获取到obj锁,正要执行show()方法,需要获取this锁
  47.                 t2.start();
  48.                 //但是1线程执行到else里的show()方法,已经获取了this锁,并且继续向下执行要获取同步代码块中的obj锁
  49.                 //而0线程占有者obj锁需要获取this锁,两线程都不释放各自占有的锁,死锁产生
  50.         }
  51. }
复制代码

作者: 乔青山    时间: 2014-3-2 14:48
李白衣 发表于 2014-3-2 12:11
线程0在flag为true时进入循环,获得锁的过程就是:obj-->this-->obj,obj和obj是同一个锁,所以线程0想要执 ...

谢谢谢谢,已经明白了,太感谢了
作者: 乔青山    时间: 2014-3-2 14:50
陪你等日出 发表于 2014-3-2 13:10
同步函数的锁是this锁,函数上的锁不一定是this锁,静态同步函数的锁是类的字节码.class,再说程序为什么会 ...

静态同步函数的锁是类的字节码,类名.class,非静态函数的锁就是this了 是么?
嗯嗯,死锁的过程明白了,太感谢了。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2