黑马程序员技术交流社区

标题: 线程同步问题,两线程交替打印,连续的三个A,B。代码如下 [打印本页]

作者: 丸子    时间: 2014-8-6 17:07
标题: 线程同步问题,两线程交替打印,连续的三个A,B。代码如下
本帖最后由 丸子 于 2014-8-28 11:02 编辑

public class ThreadExample {

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                final Service1 s=new Service1();
   
                Thread t1=new Thread(){
                        public void run(){
                                for(int i=0;i<7;i++){
                                        s.print1();
                                        try {
                                                Thread.sleep(1000);
                                        } catch (InterruptedException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }

                                }

                        }
                        
        
                };
                Thread t2=new Thread(){
                        public void run(){
                                for(int i=0;i<7;i++){
                                        s.print2();
                                        try {
                                                Thread.sleep(1000);
                                        } catch (InterruptedException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                }
                                
                        }

                };
                t1.start();
                t2.start();
        }

}
class Service1 {
        int ss=0;
        public void print1(){
                if(ss!=0)
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                synchronized(this){
                        
                        for(int i=0;i<3;i++)
                                System.out.println(Thread.currentThread().getName()+"A");
                        System.out.println();
                        
                        }
                ss=1;
                this.notify();
        }
        public  void print2(){
                if(ss!=1)
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                synchronized(this){
                        
                        for(int i=0;i<3;i++)
                                System.out.println(Thread.currentThread().getName()+"B");
                        System.out.println();
                        
                        }
                ss=0;
                this.notify();
        }
}

作者: 丸子    时间: 2014-8-6 17:08
为什么出错?
作者: 萍水相逢    时间: 2014-8-6 18:34
改过后的代码:
  1. public class ThreadExample {

  2.         public static void main(String[] args) {
  3.                 final Service1 s = new Service1();

  4.                 new Thread() {
  5.                         public void run() {
  6.                                 for (int i = 0; i < 7; i++) {
  7.                                         s.print1();
  8.                                         try {
  9.                                                 Thread.sleep(1000);
  10.                                         } catch (InterruptedException e) {
  11.                                                 e.printStackTrace();
  12.                                         }
  13.                                 }
  14.                         }
  15.                 }.start();
  16.                 new Thread() {
  17.                         public void run() {
  18.                                 for (int i = 0; i < 7; i++) {
  19.                                         s.print2();
  20.                                         try {
  21.                                                 Thread.sleep(1000);
  22.                                         } catch (InterruptedException e) {
  23.                                                 e.printStackTrace();
  24.                                         }
  25.                                 }
  26.                         }
  27.                 }.start();
  28. //                t1.start();
  29. //                t2.start();
  30.         }
  31. }

  32. class Service1 {
  33.         int ss = 0;

  34.         public synchronized void print1() {
  35.                 if (ss != 0)
  36.                         try {
  37.                                 this.wait();
  38.                         } catch (InterruptedException e) {
  39.                                 e.printStackTrace();
  40.                         }
  41. //                synchronized (this) {
  42.                         for (int i = 0; i < 3; i++)
  43.                                 System.out.println(Thread.currentThread().getName() + "-A");
  44.                         System.out.println();
  45. //                }
  46.                 ss = 1;
  47.                 this.notify();
  48.         }

  49.         public synchronized void print2() {
  50.                 if (ss != 1)
  51.                         try {
  52.                                 this.wait();
  53.                         } catch (InterruptedException e) {
  54.                                 e.printStackTrace();
  55.                         }
  56. //                synchronized (this) {
  57.                         for (int i = 0; i < 3; i++)
  58.                                 System.out.println(Thread.currentThread().getName() + "-B");
  59.                         System.out.println();
  60. //                }
  61.                 ss = 0;
  62.                 this.notify();
  63.         }
  64. }
复制代码

作者: 萍水相逢    时间: 2014-8-6 18:39
丸子 发表于 2014-8-6 17:08
为什么出错?

  原因是:在对某个对象上调用wait()方法进行线程等待(让其他竞争执行该代码的线程上锁)时,没有对该对象执行同步操作。
作者: 丸子    时间: 2014-8-6 19:00
萍水相逢 发表于 2014-8-6 18:39
原因是:在对某个对象上调用wait()方法进行线程等待(让其他竞争执行该代码的线程上锁)时,没有对该对 ...

还是不懂,为什么wait()只能放在synchronized的里面,不能在外面呢?
作者: yqj    时间: 2014-8-6 19:26
本帖最后由 yqj 于 2014-8-6 19:27 编辑

看看这样也可以(把notify()放在同步代码块中)
  1. package cn.test;

  2. public class ThreadExample {

  3.         /**
  4.          * @param args
  5.          */
  6.         public static void main(String[] args) {
  7.                 final Service1 s = new Service1();

  8.                 Thread t1 = new Thread() {
  9.                         public void run() {
  10.                                 for (int i = 0; i < 7; i++) {
  11.                                         s.print1();
  12.                                         try {
  13.                                                 Thread.sleep(1000);
  14.                                         } catch (InterruptedException e) {
  15.                                                 e.printStackTrace();
  16.                                         }

  17.                                 }

  18.                         }

  19.                 };
  20.                 Thread t2 = new Thread() {
  21.                         public void run() {
  22.                                 for (int i = 0; i < 7; i++) {
  23.                                         s.print2();
  24.                                         try {
  25.                                                 Thread.sleep(1000);
  26.                                         } catch (InterruptedException e) {
  27.                                                 e.printStackTrace();
  28.                                         }
  29.                                 }

  30.                         }

  31.                 };
  32.                 t1.start();
  33.                 t2.start();
  34.         }
  35. }

  36. class Service1 {
  37.         int ss = 0;

  38.         public void print1() {
  39.                 if (ss != 0)
  40.                         try {
  41.                                 this.wait();
  42.                         } catch (InterruptedException e) {
  43.                                 // TODO Auto-generated catch block
  44.                                 e.printStackTrace();
  45.                         }
  46.                 synchronized (this) {

  47.                         for (int i = 0; i < 3; i++)
  48.                                 System.out.println(Thread.currentThread().getName() + "A");
  49.                         System.out.println();

  50.                         ss = 1;
  51.                         this.notify();
  52.                 }
  53.         }

  54.         public void print2() {
  55.                 if (ss != 1)
  56.                         try {
  57.                                 this.wait();
  58.                         } catch (InterruptedException e) {
  59.                                 // TODO Auto-generated catch block
  60.                                 e.printStackTrace();
  61.                         }
  62.                 synchronized (this) {

  63.                         for (int i = 0; i < 3; i++)
  64.                                 System.out.println(Thread.currentThread().getName() + "B");
  65.                         System.out.println();

  66.                         ss = 0;
  67.                         this.notify();
  68.                 }
  69.         }
  70. }
复制代码


原因:对于notify()方法,jdk的说明:解除那些在该对象上调用wait()方法的线程的阻塞状态。notify()方法只能在同步方法或同步块内部调用。如果当前线程不是对象所得持有者,该方法抛出一个java.lang.IllegalMonitorStateException 异常”

所以把notify()方法放在同步代码中就ok了。
不知道解释对否,希望对lz有帮助!
作者: 丸子    时间: 2014-8-6 19:58
yqj 发表于 2014-8-6 19:26
看看这样也可以(把notify()放在同步代码块中)

原因:对于notify()方法,jdk的说明:解除那些在该对象上 ...

我把你的代码复制过来还是有错!!
作者: yqj    时间: 2014-8-6 20:11
哦,刚刚只测了一遍,又多测了几遍真的有错,以前学的时候记得是多线程的时候记得是wait()和notify()方法要放在同步代码块中忘了,以为就放notify()行了,那就要wait();和notify();都放同步代码块中,又测试了几遍应该没问题了,再出错我就不知道了
作者: 这个夏天的芬芳    时间: 2014-8-6 20:14
{:2_31:}{:2_31:}{:2_31:}{:2_31:}{:2_31:}{:2_31:}
作者: 萍水相逢    时间: 2014-8-6 21:21
丸子 发表于 2014-8-6 19:00
还是不懂,为什么wait()只能放在synchronized的里面,不能在外面呢?

我的理解是:因为synchronized (this)就是一把锁,如果wait()不放在锁里面,就会造成很多线程都堵塞在这里,但加上锁就不一样,只有一个线程再等待,这样才会安全!
作者: 丸子    时间: 2014-8-7 07:43
yqj 发表于 2014-8-6 20:11
哦,刚刚只测了一遍,又多测了几遍真的有错,以前学的时候记得是多线程的时候记得是wait()和notify()方法要 ...

好的,谢谢。费心了{:3_53:}
作者: 丸子    时间: 2014-8-7 07:45
萍水相逢 发表于 2014-8-6 21:21
我的理解是:因为synchronized (this)就是一把锁,如果wait()不放在锁里面,就会造成很多线程都堵塞在这 ...

哦,貌似理解了,非常感谢{:3_64:}
作者: 萍水相逢    时间: 2014-8-7 08:39
丸子 发表于 2014-8-7 07:45
哦,貌似理解了,非常感谢

不客气!其实帮助你的同时,自己也学到了不少东西!
作者: 小小菜鸟007    时间: 2014-8-7 09:20
线程同步,只能放在synchronized里面




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