黑马程序员技术交流社区

标题: 同步方法内嵌套使用当前对象锁的同步代码块会不会出现... [打印本页]

作者: breeze    时间: 2013-4-28 20:45
标题: 同步方法内嵌套使用当前对象锁的同步代码块会不会出现...
本帖最后由 breeze 于 2013-4-29 18:13 编辑

看下面的代码, 我在同步方法中拿到了当前对象锁, 接着在方法内声明了同步代码块, 这时候是不是应该是死锁, 但是程序运行却没有出现死锁问题
public class ThreadTest {
public static void main(String[] args) {
  final MyCode mc = new MyCode();
  
  //开启了两个线程
  new Thread() {
   public void run() {
    while (true)
     try {
     mc.print1(); //调用mc中的方法1
     } catch (InterruptedException e) {
      
     }
   }
  }.start();
  
  new Thread() {
   public void run() {
    while (true)
     try {
     mc.print2(); //调用mc中的方法2
     } catch (InterruptedException e) {
      
     }
   }
  }.start();  
}
}
//这个类有两个方法
class MyCode  {
int flag = 1;

public synchronized void print1() throws InterruptedException {  //同步方法
  synchronized(this) { //同步代码块, 这里为什么没有出现死锁, 方法拿到锁, 代码块是不是不能得到锁
   if (flag != 1)
    wait();
   System.out.print("C");
   System.out.print("S");
   System.out.print("D");
   System.out.print("N");
   System.out.print("\r\n");
   notify();
   flag = 2;
  }
}

public void print2() throws InterruptedException {
  synchronized(this) {
   if (flag != 2)
    wait();
   System.out.print("黑");
   System.out.print("马");
   System.out.print("程");
   System.out.print("序");
   System.out.print("员");
   System.out.print("\r\n");
   notify();
   flag = 1;
  }
}
}


作者: 殇_心。    时间: 2013-4-28 20:59
我的理解:
你这里同步方法和同步代码块是同一锁,都是this。
所以说是不会出现死锁的。

作者: 江南雨    时间: 2013-4-28 22:31
都是 同一个锁,这么可能会出现锁呢
作者: 孙胜    时间: 2013-4-28 22:35
synchronized(new Object)看看会不会死锁
作者: breeze    时间: 2013-4-28 22:47
孙胜 发表于 2013-4-28 22:35
synchronized(new Object)看看会不会死锁

这个不会出现死锁
作者: breeze    时间: 2013-4-28 22:51
殇_心。 发表于 2013-4-28 20:59
我的理解:
你这里同步方法和同步代码块是同一锁,都是this。
所以说是不会出现死锁的。

我的理解是在方法执行的时候拿到一个this锁, 然后方法里代码执行的时候又要拿this锁拿不到, 下面的线程也要this锁, 所以就死锁了, 还是说在同步方法中定义同步代码块他俩只会执行一次
作者: 殇_心。    时间: 2013-4-28 22:58
breeze 发表于 2013-4-28 22:51
我的理解是在方法执行的时候拿到一个this锁, 然后方法里代码执行的时候又要拿this锁拿不到, 下面的线程也 ...

死锁我觉得是这样:
A锁里面有B锁。
B锁里面有A锁。
这样就互相矛盾了。。。  有点死循环的感觉。 就死锁了。
作者: breeze    时间: 2013-4-28 23:02
殇_心。 发表于 2013-4-28 22:58
死锁我觉得是这样:
A锁里面有B锁。
B锁里面有A锁。

你这个是因为A拿不到A锁, B拿不到B锁所以死锁了, 我这个不是A拿不到A锁么, 但是不是, 我不知道这个原理是什么
作者: 张洪慊    时间: 2013-4-28 23:40
感觉你思路有点混乱.
在你的代码中自始至终就一个锁new MyCode()
  1. 分析下你的代码:
  2. public class ThreadTest {
  3. public static void main(String[] args) {
  4.   final MyCode mc = new MyCode();
  5.   
  6.   //开启了两个线程
  7.   new Thread() {
  8.    public void run() {
  9.     while (true)
  10.      try {
  11.      mc.print1(); //Thread-0执行print1代码
  12.      } catch (InterruptedException e) {
  13.       
  14.      }
  15.    }
  16.   }.start();
  17.   
  18.   new Thread() {
  19.    public void run() {
  20.     while (true)
  21.      try {
  22.      mc.print2(); //Thread-1执行print2代码
  23.      } catch (InterruptedException e) {
  24.       
  25.      }
  26.    }
  27.   }.start();  
  28. }
  29. }
  30. class MyCode  {
  31. int flag = 1;
  32. /*
  33. CPU切换Thread-0首先进入同步函数持有this锁(那么此时即使CPU切换到Thread-1,它无法执行print2,因为它没有this锁)
  34. 在进入同步代码块你这里依然用的this锁
  35. 同一把锁,Thread-0依然可以进入执行.
  36. 在这里的同步嵌套用的同一个锁,那么里面同步代码块有和没有在这里没有区别,只不过再次判断了下原锁
  37. */
  38. public synchronized void print1() throws InterruptedException {
  39.   synchronized(this) {
  40.    if (flag != 1)
  41.     wait();
  42.    System.out.print("C");
  43.    System.out.print("S");
  44.    System.out.print("D");
  45.    System.out.print("N");
  46.    System.out.print("\r\n");
  47.    notify();
  48.    flag = 2;
  49.   }
  50. }

  51. public void print2() throws InterruptedException {
  52.   synchronized(this) {
  53.    if (flag != 2)
  54.     wait();
  55.    System.out.print("黑");
  56.    System.out.print("马");
  57.    System.out.print("程");
  58.    System.out.print("序");
  59.    System.out.print("员");
  60.    System.out.print("\r\n");
  61.    notify();
  62.    flag = 1;
  63.   }
  64. }
  65. }
  66. /*
  67. 关于死锁:
  68. 在操作系统中解释:(大同小异)
  69. 所谓死锁,是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
  70. 假如有一双筷子,每支筷子(a,b)相当于一把锁,2个人p1,p2(两个线程)
  71. p1持有a,为了吃饭(为了向下执行),索要b
  72. p2持有b,同上,索要a
  73. 这时候,两者互不相让发生死锁.
  74. 但是有一种很和谐情况:p1持有了a,再持有b->吃完饭(执行完)->释放了a,b->p2持有a,在持有b->执行完.....
  75. */
复制代码

作者: 殇_心。    时间: 2013-4-29 09:57
breeze 发表于 2013-4-28 23:02
你这个是因为A拿不到A锁, B拿不到B锁所以死锁了, 我这个不是A拿不到A锁么, 但是不是, 我不知道这个原理是 ...

我这样理解:
你现在拿到了房子(同步函数)的门钥匙(this)。
用钥匙打开门进到房子里面,
发现这里面一道门也是用同样的锁。(同步代码块)
你同样可以拿钥匙打开。
然后你退出房子的时候,你把钥匙归还。
作者: Neverbelazy    时间: 2013-4-29 09:57
1. 把线程当成是人,一个对象对应一个锁(但是这个锁可以有很多的副本,例如你程序中this锁的嵌套),程序块是一个房间。
2. 同步一段代码的过程,相当于,一个人进入了一个房间,上了锁,但是同时把锁上的钥匙拿走了。
3.所以这个人只要还持有这个锁的钥匙就还可以继续开启这类锁锁住的门。比如,人上this锁进了房间,发现房间内的厕所门也被同样的this锁锁上了,不过没关系,哥们有钥匙啊,就开门进去了
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4. 所以在这个类比中,和日常生活中锁和钥匙的比喻有一点不同,这里面,一个名字的锁,可以有多个副本,锁在多个门上,但是钥匙只有一把,哪个人(线程)拿到了,哪个人(线程)就能进入门(同步代码)内。




作者: 殇_心。    时间: 2013-4-29 09:58
Neverbelazy 发表于 2013-4-29 09:57
1. 把线程当成是人,一个对象对应一个锁(但是这个锁可以有很多的副本,例如你程序中this锁的嵌套),程序 ...

哥们。我们想法差不多哦。。```
都是用房子来比喻。。
作者: Neverbelazy    时间: 2013-4-29 10:03
殇_心。 发表于 2013-4-29 09:58
哥们。我们想法差不多哦。。```
都是用房子来比喻。。

:handshake:lol
作者: 殇_心。    时间: 2013-4-29 10:03
Neverbelazy 发表于 2013-4-29 10:03

:handshake
作者: breeze    时间: 2013-4-29 13:33
Neverbelazy 发表于 2013-4-29 09:57
1. 把线程当成是人,一个对象对应一个锁(但是这个锁可以有很多的副本,例如你程序中this锁的嵌套),程序 ...

比喻的太好了,我明白了,感谢




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