Java多线程之join疑问

luojinping 2011-10-14 11:39:54

public class Test extends Thread
{
public static volatile int n = 0;

public void run()
{
for (int i = 0; i < 10; i++, n++)
try
{
sleep(1); // 为了使运行结果更随机,延迟3毫秒
}
catch (Exception e)
{
}
}
public static void main(String[] args) throws Exception
{
Thread threads[] = new Thread[100];
for (int i = 0; i < threads.length; i++) // 建立100个线程
threads[i] = new Test();
for (int j = 0; j < threads.length; j++) // 运行刚才建立的100个线程
{
threads[j].start();
threads[j].join();
}
System.out.println("n=" + Test.n);
}
}

结果为:1000


public class Test extends Thread
{
public static volatile int n = 0;

public void run()
{
for (int i = 0; i < 10; i++, n++)
try
{
sleep(1); // 为了使运行结果更随机,延迟3毫秒
}
catch (Exception e)
{
}
}
public static void main(String[] args) throws Exception
{
Thread threads[] = new Thread[100];
for (int i = 0; i < threads.length; i++) // 建立100个线程
threads[i] = new Test();
for (int j = 0; j < threads.length; j++) // 运行刚才建立的100个线程
{
threads[j].start();
}

for (int k = 0; k < threads.length; k++) // 100个线程都执行完后继续
threads[k].join();
System.out.println("n=" + Test.n);
}
}

结果接近1000.大多数为900到998之间,很不确定。

请问这是神马原因啊?
...全文
210 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
qybao 2011-10-14
  • 打赏
  • 举报
回复
第一种情况
threads[j].start();
threads[j].join();
两个是连在一起的,所以start方法启动后,就开始jion,就会等待j线程结束,才进入下一个for循环

第二种情况
threads[j].start();
...
threads[k].jion();
线程调用start后,什么时候执行由CPU决定,所以在进入k循环之前,j线程可能有一部分就随机执行了,等到进入k循环的时候,k线程jion有一部分已经失去意义,因为有些j线程早已执行结束,所以造成数据不同步
qybao 2011-10-14
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 luojinping 的回复:]
嗯,n++不是原子操作我知道。那请问,是不是threads[1].join()执行后,就必须等到threads[1].run()执行完才继续运行程序,也就是进行下一次循环操作,处理threads[2].start();……
[/Quote]
就是这样的
thread[1].join()主线程就会等待thread[1]的run结束才会继续下一次循环,才会执行thread[2]的start,这样就不会有多个线程同时执行n++
luojinping 2011-10-14
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 luojinping 的回复:]

引用楼主 luojinping 的回复:
Java code

public class Test extends Thread
{
public static volatile int n = 0;

public void run()
{
for (int i = 0; i < 10; i++, n++)
try
{
……

“因为有些j线程早已执行结束,所以造成……
[/Quote]
谢谢~我还有点疑惑。
n++不是原子操作我知道。那请问,是不是threads[1].join()执行后,就必须等到threads[1].run()执行完才继续运行程序,也就是进行下一次循环操作,处理threads[2].start();……
luojinping 2011-10-14
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 luojinping 的回复:]

引用楼主 luojinping 的回复:
Java code

public class Test extends Thread
{
public static volatile int n = 0;

public void run()
{
for (int i = 0; i < 10; i++, n++)
try
{
……

“因为有些j线程早已执行结束,所以造成……
[/Quote]
嗯,n++不是原子操作我知道。那请问,是不是threads[1].join()执行后,就必须等到threads[1].run()执行完才继续运行程序,也就是进行下一次循环操作,处理threads[2].start();……
BearKin 2011-10-14
  • 打赏
  • 举报
回复
[Quote=引用楼主 luojinping 的回复:]
Java code

public class Test extends Thread
{
public static volatile int n = 0;

public void run()
{
for (int i = 0; i < 10; i++, n++)
try
{
……
[/Quote]

假设当前有两个线程A、B 线程A的一部分功能依赖线程B的执行结果
两个线程一开始是一起执行A线程将可独立执行的代码执行完毕后等待B的执行结束 这个时候就可以用join
qybao 2011-10-14
  • 打赏
  • 举报
回复
n++相当于n = n + 1;
这样的操作是由几个指令来完成的
首先从内存中读取n的值,放到寄存器中,然后对寄存器的操作数执行+1,然后再把寄存器的结果写入n的内存中
那么好了,多个线程执行,假如线程1线从n的内存读取n的值,开始n的值为0(线程1的寄存器的值是0),然后线程1没来得及执行后面的操作CPU就被收回,假设这时线程2获得CPU权限执行,那么线程2也会从n的内存读入n的值,然后执行操作直到n=10(此时n的内存的值是10),然后线程2的CPU权限被收回,然后假设此时线程1又获得了CPU权限执行,那么,刚才知道,线程1的寄存器的值是0,然后执行后面+1操作,然后把寄存器的值写入n的内存,可见,此时n的内存的值又变回了1,也就是说线程1的n并不是在线程2的n的基础上进行累加的,而是在自己读入的n的值的基础上进行累加的,所以这样就造成了结果少了线程2累加的10
正是因为多线程的操作会引起这样的不同步问题,才有了synchronized这样的同步解决方案。LZ再好好理解理解。
luojinping 2011-10-14
  • 打赏
  • 举报
回复
[Quote=引用楼主 luojinping 的回复:]
Java code

public class Test extends Thread
{
public static volatile int n = 0;

public void run()
{
for (int i = 0; i < 10; i++, n++)
try
{
……
[/Quote]
“因为有些j线程早已执行结束,所以造成数据不同步”对于这句话,有些不能理解。如果有些j线程已经结束则说明其已经运行完了run()函数,那么Test.n应该就相应地增加了数个10。那么到了join()函数运行后,后面的线程一个一个顺序执行完,那Test.n又相应地增加了数个10。那最后结果不应该是对的,就是1000吗?
内容概要:本文详细介绍了利用Simulink进行变压器开路试验的电路连接配置与仿真实现方法,重点在于通过仿真手段还原实际电力系统中变压器在空载条件下的电气特性,从而深入理解其工作原理与性能表现。文章作为电力系统仿真系列研究的一部分,系统阐述了从电路模型搭建、参数设定、仿真运行到结果分析的完整流程,突出展示了MATLAB/Simulink在电力设备建模与教学科研中的强大功能与应用价值。; 适合人群:具备电力系统基础知识,熟悉MATLAB/Simulink仿真环境,从事电气工程、自动化及相关领域的研发人员,以及高年级本科生和研究生。; 使用场景及目标:①掌握变压器开路试验的基本原理与Simulink仿真建模的具体步骤;②通过仿真实验深入理解空载电流、铁芯损耗及励磁特性等关键参数的物理意义;③为后续开展变压器短路试验、暂态过程分析以及其他电力设备的仿真研究奠定理论与实践基础。; 阅读建议:建议结合Simulink软件动手实践,逐步构建并调试电路模型,重点关注各元件参数的设置方法与测量模块的应用技巧,同时推荐参考文中提及的其他相关仿真案例进行拓展学习,以全面提升对电力系统仿真实践的整体认知与操作能力。

51,409

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧