黑马程序员技术交流社区

标题: 毕老师课程(多线程安全问题)在多核处理器上怎么解决 [打印本页]

作者: 周恺    时间: 2012-6-18 00:37
标题: 毕老师课程(多线程安全问题)在多核处理器上怎么解决
好吧,首先我承认我是菜鸟.

今天看完<多线程安全问题>视频后,自己仿照毕老师的代码写了一遍,但是运行结果却和毕老师的不大一样.
  1. class Matter implements Runnable
  2. {
  3. private int i=100;
  4. public void run()
  5. {
  6. Object o=new Object();
  7. while(true)
  8. {
  9. synchronized(o)
  10. {
  11. if (i>1)
  12. {
  13. try
  14. {
  15. Thread.sleep(10);
  16. }
  17. catch (Exception e)
  18. {

  19. }
  20. System.out.println(Thread.currentThread().getName()+"----"+i--);
  21. }
  22. }
  23. }
  24. }

  25. }

  26. class ThreadTest
  27. {
  28. public static void main(String[] args)
  29. {
  30. Matter m=new matter();
  31. Thread t1=new Thread(m,"t1");
  32. Thread t2=new Thread(m,"t2");
  33. Thread t3=new Thread(m,"t3");
  34. Thread t4=new Thread(m,"t4");
  35. t1.start();
  36. t2.start();
  37. t3.start();
  38. t4.start();
  39. }
  40. }
复制代码
原则上说,如果多线程同时操作共享数据后,加上synchronized锁定了代码块,那么共享数据应该是从1到100每个数只打印一次,但是我运行后有些数却有打印两次的情况.
可能是因为我的电脑是双核处理器的,我想请问的是,如果这是由于多核处理器造成的问题,那么这个程序在多核处理器上应该怎么改进呢?

作者: 黑马_张佳超    时间: 2012-6-18 01:16
java中的多线程与CPU核数貌似没有关系吧?
多核CPU也只不过是减少其他程序执行的等待时间。
楼主代码中while循环没有结束条件,代码中第33行matter应为Matter
作者: 周恺    时间: 2012-6-18 01:26
黑马_张佳超 发表于 2012-6-18 01:16
java中的多线程与CPU核数貌似没有关系吧?
多核CPU也只不过是减少其他程序执行的等待时间。
楼主代码中whil ...

恩,是没有结束条件,故意的,但是打印结果真的和视频上不一样哦,当多条语句在操作同一个线程时,一个线程对多条语句只执行一部分,还没有执行完,另一个线程参与进来执行,会导致共享数据的错误.双核工作的方式就是一核执行一个线程从而进行分工,提高运行效率,那么也可能会出现以上共享数据操作的异常啊.比如A核在执行过程中,还没有执行完,B核就参与进来对共享数据进行操作,难道没有可能吗?synchronized在单核时锁定是ok的,但是到了双核就纠结了.
作者: 李元峰    时间: 2012-6-18 01:30
单核就是一个处理器内有一个物理运算核心单元,只能同时处理一个任务线程,而双核就是一个处理器内集成两个物理运算核心单元,可以同时处理两个任务线程,同理,四核也就可以同时处理四个任务线程。当单核心处理器面对两个或多个任务同时运行的话,因为它同时只能处理一个任务线程,所以它会分时间段来处理每一个任务,例如,第一秒处理A任何,没做完,停止一下,第二秒又去处理B任务,没做完,暂停一下,第三秒再次反回去处理A任务,然后第四秒又处理B任务,如此类推,直到两个任务都完成。虽然看起来两个任务同时在进行,但并不是同时在处理。而双核就可以两个任务同时进行,理论上时间效率就翻倍了。所以双核或多核是在多任务多线程的情况下占点优势,在单任务单线程的情况下就不一定了。


作者: 李元峰    时间: 2012-6-18 01:31
楼主要理解 cpu 处理任务的原理
作者: 周恺    时间: 2012-6-18 01:34
李元峰 发表于 2012-6-18 01:30
单核就是一个处理器内有一个物理运算核心单元,只能同时处理一个任务线程,而双核就是一个处理器内集成两个 ...

.....我了解它们的原理,
你的答案是在http://zhidao.baidu.com/question/160096097.html上copy的吧..
作者: 孙安庆    时间: 2012-6-18 01:37
LZ,请您赶快把第6行放到第3行,不然会出大事的{:soso__11196047724299059215_1:}

现在的状况是作为锁的对象,被定义在了run()方法内,这意味着什么?同步四个线程不是同一个锁。啊!真的不是
不信请看毕老师总结的两个前提
作者: 周恺    时间: 2012-6-18 01:49
孙安庆 发表于 2012-6-18 01:37
LZ,请您赶快把第6行放到第3行,不然会出大事的

现在的状况是作为锁的对 ...

正解,果然粗大事了.:lol
谢谢了兄弟.
作者: 黑马_张佳超    时间: 2012-6-18 02:40
周恺 发表于 2012-6-18 01:26
恩,是没有结束条件,故意的,但是打印结果真的和视频上不一样哦,当多条语句在操作同一个线程时,一个线程对 ...

你试试将同步域声明为private final的成员变量
把Object o = new Object();-->private final Object o = new Object();
作者: 曾祥彬    时间: 2012-6-18 07:46
本帖最后由 曾祥彬 于 2012-6-18 12:00 编辑

不知道你学过操作系统没?
线程分为两种:
1、操作系统级的线程:线程由操作系统实现
2、用户级的线程:线程由用户实现
操作系统级别的线程是由操作系统管理的,如果CPU有多核,那么你的多线程程序是可以同时运行在不同的核上面的。
用户级别的线程由用户程序实现,放在java里面就是由java虚拟机实现和管理线程,那么在一段时间内所有的线程只可能在一个CPU的其中一个核上执行,不可能出现一个线程在核1上运行而另一个线程在核二上运行。
我的电脑也是双核的,但是程序运行正常,代码如下:
  1. package heima.lt.generator;

  2. class Matter implements Runnable {
  3.         private int i = 100;
  4.         private static final Object o = new Object();  // 改成这样,也就是说全部线程公用一个锁对象,这样就可以了
  5.         public void run() {
  6.                 while (true) {
  7. // Object o = new Object();   // 把这里注释掉
  8.                         synchronized (o) {
  9.                                 if (i > 1) {
  10.                                         try {
  11.                                                 Thread.sleep(10);
  12.                                         } catch (Exception e) {

  13.                                         }
  14.                                         System.out.println(Thread.currentThread().getName()
  15.                                                         + "----" + i--);
  16.                                 }
  17.                         }
  18.                 }
  19.         }

  20. }
  21. // 加个public 表明这个类是这个文件的主类
  22. public class ThreadTest {
  23.         public static void main(String[] args) {
  24.                 Matter m = new Matter();
  25.                 Thread t1 = new Thread(m, "t1");
  26.                 Thread t2 = new Thread(m, "t2");
  27.                 Thread t3 = new Thread(m, "t3");
  28.                 Thread t4 = new Thread(m, "t4");
  29.                 t1.start();
  30.                 t2.start();
  31.                 t3.start();
  32.                 t4.start();
  33.         }
  34. }
复制代码

作者: 郭凯敏    时间: 2012-6-30 00:45
没次run()一下会产生一个新的锁,你自然是锁不住的啊




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