黑马程序员技术交流社区

标题: 关于实现Runnable接口创建多线程共享实例属性的困惑 [打印本页]

作者: 黑马王冬冬    时间: 2012-7-15 00:05
标题: 关于实现Runnable接口创建多线程共享实例属性的困惑
  1. 1 public class SecondThread implements Runnable
  2.   2 {
  3.   3   private int i;
  4.   4
  5.   5   public void run()
  6.   6   {
  7.   7     for (;i < 10000;i++)
  8.   8     {
  9.   9       System.out.println(Thread.currentThread().getName() + " " + i);
  10. 10     }
  11. 11   }
  12. 12
  13. 13   public static void main(String[] args)
  14. 14   {
  15. 15     for (int i = 0;i < 100;i++)
  16. 16     {
  17. 17       System.out.println(Thread.currentThread().getName() + " " + i);
  18. 18
  19. 19       if (i == 20)
  20. 20       {
  21. 21         SecondThread st = new SecondThread();
  22. 22
  23. 23         new Thread(st,"新线程1").start();
  24. 24         new Thread(st,"新线程2").start();
  25. 25       }
  26. 26     }
  27. 27   }
  28. 28 }
  29. 29
复制代码

Selection_006.png (12.34 KB, 下载次数: 114)

新线程1和新线程2在第一次切换时打印的i值相同

新线程1和新线程2在第一次切换时打印的i值相同

作者: 黑马王冬冬    时间: 2012-7-15 00:11
实现Runnable接口创建多个线程可以共享同一个线程类的实例属性。
但我在实际的运行过程中发现,两个线程会在第一次切换时,打印相同的i值,请问各位同学,这如何解释?
作者: 黑马刘涛    时间: 2012-7-15 00:12
本帖最后由 黑马刘涛 于 2012-7-15 01:23 编辑
  1. public class SecondThread implements Runnable
  2. {
  3. private int i;
  4. public void run()
  5. {

  6. for (;i < 200;i++)
  7. synchronized(this)// i  是共享资源,用同步代码块上锁。类似售票窗口,不能几个窗口同时打同一张票吧。
  8. {
  9. System.out.println(Thread.currentThread().getName() + " " + i);
  10. }
  11. }

  12. public static void main(String[] args)
  13. {
  14. for (int i = 0;i < 100;i++)
  15. {
  16. System.out.println(Thread.currentThread().getName() + " " + i);
  17. if (i == 20)
  18. {
  19. SecondThread st = new SecondThread();
  20. new Thread(st,"新线程1").start();
  21. new Thread(st,"新线程2").start();
  22. }
  23. }
  24. }
  25. }
复制代码

作者: 黑马王冬冬    时间: 2012-7-15 00:15
黑马刘涛 发表于 2012-7-15 00:12
对共享资源没上锁。

那么为什么总是在第一次切换时出现这种情况,而且似乎总是出现一次?
作者: 王宝康    时间: 2012-7-15 00:39
  1. package thread;
  2. public class SecondThread implements Runnable
  3.    {
  4.      private int i;
  5.    
  6.      public void run()
  7.     {
  8.        for (;i < 1000;i++)
  9.        synchronized(this){
  10.          System.out.println(Thread.currentThread().getName() + " " + i);
  11.      }
  12.    }

  13.    public static void main(String[] args)
  14.    {
  15.      for (int i = 0;i < 100;i++)
  16.      {
  17.        System.out.println(Thread.currentThread().getName() + " " + i);

  18.        if (i == 20)
  19.        {
  20.          SecondThread st = new SecondThread();

  21.          new Thread(st,"新线程1").start();
  22.          new Thread(st,"新线程2").start();
  23.        }
  24.      }
  25.    }
  26. }
复制代码
对共享资源上锁可以消除你所说的情况,至于你说的为什么总是在第一次切换时出现,观望中....
作者: 张莹莹    时间: 2012-7-15 01:38
首先,在多线程环境下对Runnable的实例变量做写操作都是线程不安全的
例如:

至于为什么会出现第一次切换时输出相同的结果,而之后不会出现相同的结果,应该是因为线程对i做修改后就立马输出了,察觉不到错误的结果,我们可以做如下实验,在原来的代码上加上sleep,如下图所示

就会发现,之后的切换也会出现相同的结果
结论,多个Thread对同一个Runnable中的实例变量做操作时,必须加锁,否则就是线程不安全的,结果不可预测。对Runnable中的静态变量做修改也必须加锁,否则也是线程不安全的。





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