请选择 进入手机版 | 继续访问电脑版
本站特色:极好的技术研究氛围!所有技术交流,必有回复!

疯狂Java联盟

 找回密码
 加入联盟
查看: 4530|回复: 9

《疯狂Java讲义》多线程我晕了

[复制链接]
发表于 2010-11-10 10:48:05 | 显示全部楼层 |阅读模式
最近看到这部分,关于实现runnable接口创建线程类的源代码如下
  1. public class SecondThread implements Runnable{
  2.     private int i;
  3.     public void run(){
  4.             for (; i < 100; i++) {
  5.                         System.out.println(Thread.currentThread().getName()+" "+i);
  6.                 }
  7.     }
  8.         public static void main(String[] args) {
  9.                 for (int i = 0; i < 100; i++) {
  10.                         System.out.println(Thread.currentThread().getName()+" "+i);
  11.                         if(i == 20){
  12.                                 SecondThread sThread = new SecondThread();
  13.                                 new Thread(sThread,"first thread").start();
  14.                                 new Thread(sThread,"second thread").start();
  15.                         }
  16.                 }
  17.         }

  18. }
复制代码
书上说多条县城可以共享同一个线程类(即target)的实例属性,可我的运行结果却不是这样的啊,怎么回事啊,我晕了,大家帮帮我。
不会插截图,就把部分结果拷过来吧。
  1. ...
  2. main 19
  3. main 20
  4. first thread 0
  5. first thread 1
  6. first thread 2
  7. main 21
  8. first thread 3
  9. second thread 3
  10. second thread 5
  11. second thread 6
  12. second thread 7
  13. second thread 8
  14. second thread 9
  15. second thread 10
  16. second thread 11
  17. second thread 12
  18. second thread 13
  19. second thread 14
  20. second thread 15
  21. second thread 16
  22. first thread 4
  23. main 22
  24. second thread 17
  25. first thread 18
  26. main 23
  27. second thread 19
  28. ...
复制代码
怎么乱乱的,看不懂啊。为什么会这样。
发表于 2010-11-10 11:10:27 | 显示全部楼层
main 线程是独立的,与两个子线程并没有任何关系。

两个子线程:first thread 18、second thread 17,很明显他们共享同一个target
你看他们打印的数字是连续的。
 楼主| 发表于 2010-11-10 11:38:28 | 显示全部楼层

回复 2# kongyeeku 的帖子

可是
first thread 3
second thread 3
还有
first thread 4
感觉不太符合吧,不太理解啊
发表于 2010-11-10 14:54:02 | 显示全部楼层

回复 3# ruixingge 的帖子

是对的。

这就是线程安全问题,两个线程共享同一个target,因此会并发修改同一个i变量。
你看到了
first thread 3
second thread 3
second thread 5
second thread 6
但他们并没有输出4,两次输出了3.
发表于 2010-11-10 15:47:49 | 显示全部楼层
老师,有以下不明白之处:
1、既然两个线程共享同一个target,那么怎么会同时出现<first thread 3> 和<second thread 3>都是3的情况呢?
2、如果同步的话,为什么会<first thread 4> 输出在<second thread 5>之后呢?当<second thread 16>被输出之后,应该不可能输出<first thread 4> 啊?可能应该输出<first thread 17>啊?

以上请老师解答,谢谢!
 楼主| 发表于 2010-11-10 16:40:57 | 显示全部楼层

回复 4# kongyeeku 的帖子

刚看了线程安全问题,原来如此,那这个类能不能通过同步方法变得安全呢。想了半天不知道怎么改代码。
发表于 2010-11-10 16:52:49 | 显示全部楼层
添加同步化方法,Synchronize
发表于 2010-11-10 22:11:15 | 显示全部楼层

回复 5# 秋风飘涩落 的帖子

1、既然两个线程共享同一个target,那么怎么会同时出现<first thread 3> 和<second thread 3>都是3的情况呢?
这很容易出现,我甚至可通过方法控制经常出现。
假设第一条线程刚刚执行了
System.out.println(Thread.currentThread().getName()+" "+i);,此时i的值是3(还没有执行i++)
——线程切换到第二条线程,此时第二条也执行下面语句
System.out.println(Thread.currentThread().getName()+" "+i);,

此时就看到两个都是3的情况。

2、如果同步的话,为什么会<first thread 4> 输出在<second thread 5>之后呢?当<second thread 16>被输出之后,应该不可能输出<first thread 4> 啊?可能应该输出<first thread 17>啊?
这不是什么同步,还是两个线程共享数据的问题,
第一条线程执行
System.out.println(Thread.currentThread().getName()+" "+i);,
比如此时i是4、但此时执行了这条语句之后,IO没有输出,
——线程切换,切换到第二条线程,
第二条线程执行一段时间就是你看到的4、5、6、7.。。。

当线程切换回来时,第一条线程才输出 4。
——这种情况出现的概率要略小。

你要判断是否共享同一个i很简单,如果是两个i,两个线程应该数出200次。
如果共享同一个i,那之输出100次。
发表于 2010-11-11 09:20:43 | 显示全部楼层
明白了,谢谢老师,多个线程共享一个target,但是CPU还是有先后执行之分的,但是共享数据还是可能出现问题的。
 楼主| 发表于 2010-11-11 14:42:34 | 显示全部楼层
我能用lock锁定吗,看看我改的代码,为什么运行除了main线程外只能有一个线程的数据。
  1. import java.util.concurrent.locks.ReentrantLock;

  2. public class SecondThread implements Runnable {
  3.         private int i;
  4.         private final ReentrantLock lock = new ReentrantLock();

  5.         public void run() {

  6.                 for (; i < 100; i++) {
  7.                         lock.lock();
  8.                         try {
  9.                                 System.out.println(Thread.currentThread().getName() + " " + i);
  10.                         } finally {
  11.                                 lock.unlock();
  12.                         }
  13.                 }

  14.         }

  15.         public static void main(String[] args) {
  16.                 for (int i = 0; i < 100; i++) {
  17.                         System.out.println(Thread.currentThread().getName() + " " + i);
  18.                         if (i == 20) {
  19.                                 SecondThread sThread = new SecondThread();

  20.                                 new Thread(sThread, "first thread").start();
  21.                                 new Thread(sThread, "second thread").start();

  22.                         }
  23.                 }
  24.         }

  25. }
复制代码
您需要登录后才可以回帖 登录 | 加入联盟

本版积分规则

视频、代码、电子书下载
请关注"疯狂图书"公众号
QQ交流1群: 545923995  未满
微信群请扫二维码
QQ交流1群:
545923995
(未满)

小黑屋|手机版|Archiver|疯狂Java联盟 ( 粤ICP备11094030号 )

GMT+8, 2019-8-26 00:28 , Processed in 0.177651 second(s), 8 queries , File On.

快速回复 返回顶部 返回列表