忘记密码   免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 10817 | 回复: 4

关于Java 线程的一个问题 [复制链接]

论坛徽章:
0
发表于 2016-07-16 08:37 |显示全部楼层
前几天,在敲到一个代码,碰到如下情况:
  1.         @Override
  2.                 public void run()
  3.                 {
  4.                         while(true)       
  5.                         {
  6. // 注释句在此                        System.out.println(flag);
  7.                                         if (flag)       
  8.                                         {
  9.                                                 System.out.println("flag is true");       
  10.                                                 // 当标识位为true时,执行到这里,转为false
  11.                                                 flag = false;
  12.                                         }
  13.                         }
  14.                 }
复制代码
情况是,我在外部改变flag的值,每隔0.5秒就在外部将flag设置为true。结果这段代码中注释句去掉注释的话,会有"flag is true"的输出,但是注释加上的话,就永远不会输出"flag is true"
有谁可以给出个合理解释吗?

全部代码如下:

  1. class MyThread extends Thread
  2. {
  3.         // 设置标识位
  4.         private boolean flag = false;
  5.         public void setFlag()
  6.         {
  7.                 flag = true;       
  8.         }
  9.         // 线程执行
  10.         @Override
  11.                 public void run()
  12.                 {
  13.                         while(true)       
  14.                         {
  15. //                                        System.out.println(flag);
  16.                                         if (flag)       
  17.                                         {
  18.                                                 System.out.println("flag is true");       
  19.                                                 // 当标识位为true时,执行到这里,转为false
  20.                                                 flag = false;
  21.                                         }
  22.                         }
  23.                 }

  24.         public static void main(String[] args)
  25.         {
  26.                 MyThread t = new MyThread();
  27.                 t.start();
  28.                 // 每隔0.5秒设置标识位为true
  29.                 while (true)
  30.                 {
  31.                         try{
  32.                                 Thread.sleep(500);       
  33.                         } catch (InterruptedException e)       
  34.                         {}

  35.                         t.setFlag();
  36.                 }
  37.         }
  38. }
复制代码

论坛徽章:
1
15-16赛季CBA联赛之新疆
日期:2017-03-09 12:33:45
发表于 2016-07-18 12:38 |显示全部楼层
本帖最后由 jeppeter 于 2016-07-18 12:42 编辑

我只修改了一个地方就可以使你的代码运行成功了。
  1. public class MyThread extends Thread {
  2.     [color=Red]private volatile boolean flag = false;[/color]
  3.     public void setFlag() {
  4.         flag = true;
  5.     }
  6.     // 线程执行
  7.     @Override
  8.     public void run() {
  9.         while (true) {
  10.             if (flag) {
  11.                 System.out.println("flag is true");
  12.                 flag = false;
  13.             }
  14.         }
  15.     }

  16.     public static void main(String[] args) {
  17.         MyThread t = new MyThread();
  18.         t.start();
  19.         while (true) {
  20.             try {
  21.                 Thread.sleep(500);
  22.             } catch (InterruptedException e)
  23.             {}

  24.             t.setFlag();
  25.         }
  26.     }
  27. }
复制代码

论坛徽章:
1
15-16赛季CBA联赛之新疆
日期:2017-03-09 12:33:45
发表于 2016-07-18 12:41 |显示全部楼层
本帖最后由 jeppeter 于 2016-07-18 12:43 编辑

我只修改了一个地方就可以使你的代码运行成功了,就是flag添加了volatile属性。
  1. public class MyThread extends Thread {
  2.     private volatile boolean flag = false;
  3.     public void setFlag() {
  4.         flag = true;
  5.     }
  6.     // 线程执行
  7.     @Override
  8.     public void run() {
  9.         while (true) {
  10.             if (flag) {
  11.                 System.out.println("flag is true");
  12.                 flag = false;
  13.             }
  14.         }
  15.     }

  16.     public static void main(String[] args) {
  17.         MyThread t = new MyThread();
  18.         t.start();
  19.         while (true) {
  20.             try {
  21.                 Thread.sleep(500);
  22.             } catch (InterruptedException e)
  23.             {}

  24.             t.setFlag();
  25.         }
  26.     }
  27. }
复制代码

论坛徽章:
0
发表于 2016-11-27 16:14 |显示全部楼层
上面的代码 是不具备线程安全性的.  "结果这段代码中注释句去掉注释的话,会有"flag is true"的输出,但是注释加上的话,就永远不会输出"flag is true" "
你看到的这个输出结果是不可控的, 这里一共有两个线程 : 1 main方法, 2 t.start()
两个线程可以同时操作 对象t的 flag属性, 有可能main方法刚刚调用完 t.setFlag()方法 第二个线程就执行了 flag = false , 而main方法中的第二次循环还没有来得及第二次调用setFlag()方法 . t.start()线程的第二次循环就已经执行到了if(flag),而此时 flag = false. 所以不输出 flag is true. (跟你睡眠0.5秒与否关系不大,只是不睡眠,打印flag is true的可能性会比较大)
输出结果会受 两个线程的执行进度影响, 而我们几乎无法控制这两个线程的执行进度,即使你对线程设定了执行优先级. 所以最后的输出结果是完全不可预期的,你看到的结果只是一个现象,可能同样的代码你放到不同的机器上结果又会不同.跟你的注释句也没什么关系. 至于你问为什么会看到这样的输出结果, 只能说 不可控 什么输出结果都有可能.
所以最好使用synchronized来控制线程同步,保证某些代码不会被 不同线程同时执行, 比如这里 对flag值的操作
您需要登录后才可以回帖 登录 | 注册

本版积分规则

第67期:Neo4j图数据库平台架构最佳实践
【微学堂】10月18日 20:00(周四)

当下,数据的规模和类型每时每刻都在呈几何级数的增长,仅能够管理大量的数据是不够的,关键是能从海量数据中发掘出有用的信息,特别是数据之间的关联,能高效存储和处理数据之间关联的新型数据库为图数据库。 本讲座将介绍Neo4j图数据库的基本概念、设计特点、架构和经典应用场景实战分享。

进入课堂>>
  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802020122
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:wangnan@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP