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之间,很不确定。

请问这是神马原因啊?
...全文
211 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吗?

51,408

社区成员

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

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