Java中的多线程未按预期工作
第一个代码并不总是显示总和为1000,因此我找到了解决问题的方法,但为什么第一个代码不起作用?结果是高度不一致的,我知道在这种情况下使用synchronized没有任何作用,但我只是在尝试Java中的多线程未按预期工作,java,multithreading,Java,Multithreading,第一个代码并不总是显示总和为1000,因此我找到了解决问题的方法,但为什么第一个代码不起作用?结果是高度不一致的,我知道在这种情况下使用synchronized没有任何作用,但我只是在尝试 class Thread1 extends Thread{ int[] count; int[] event; Thread1(int[] event, int[] count){ this.event=event; this.count=count;
class Thread1 extends Thread{
int[] count;
int[] event;
Thread1(int[] event, int[] count){
this.event=event;
this.count=count;
}
public void run(){
for(int i=0; i<500; i++){
int x = event[i];
synchronized (count){
count[x]++;
}
}
}
}
class Thread2 extends Thread{
int[] count;
int[] event;
Thread2(int[] event, int[] count){
this.event=event;
this.count=count;
}
public void run(){
for(int i=500; i<1000; i++){
int x = event[i];
synchronized (count){
count[x]++;
}
}
}
}
public class Learning {
public static void main(String[] args) {
Random random = new Random();
int[] event = new int[1000];
for(int i=0; i<event.length; i++){
event[i] = random.nextInt(3);
}
Thread1 a = new Thread1(event, new int[3]);
Thread2 b = new Thread2(event, new int[3]);
a.start();
b.start();
int second = a.count[1]+b.count[1];
int third = a.count[2]+b.count[2];
int first = a.count[0]+b.count[0];
System.out.println(first);
System.out.println(second);
System.out.println(third);
System.out.println("SUM--> "+(first+second+third));
}
}
class Thread1扩展了线程{
int[]计数;
int[]事件;
线程1(int[]事件,int[]计数){
这个。事件=事件;
这个.count=count;
}
公开募捐{
对于(int i=0;i,Thread1
和Thread2
类使用各自的count
对象进行同步
问题在于,您可以这样实例化它们:
Thread1 a = new Thread1(event, new int[3]);
Thread2 b = new Thread2(event, new int[3]);
看到了吗
您正在将不同的数组传递给两个线程。如果两个线程使用不同的对象作为其计数,则无法实现互斥或正确的内存可见性
在进一步检查中,似乎无论如何都不需要同步块。(您不需要互斥,并且您可以得到某些保证,子线程将看到正确初始化的数组,因为start()
以前发生过。)
但是,很明显,有必要将主线程中的两个子线程连接起来,原因如下:
如果不join()
,则无法在主线程查看结果之前确定子线程是否已完成
如果不join()
,则存在潜在的内存异常…即使子线程在主线程查看计数之前都已终止。(join()
调用在子线程和主线程之间施加了“发生在前”关系。)
您尝试使用stop()
的解决方案是假的,原因如下:
stop()
方法不推荐使用,因为它很危险。不应使用它
stop()
方法没有指定的同步效果
基于文档化的语义(例如它们),调用stop()
不应该解决问题
一般来说,“随机尝试”并不是修复并发错误的好策略。随机尝试很有可能不会修复错误,而是将其从频繁出现的错误转变为很少出现的错误……或者只在不同的Java平台上进行测试
为什么它看起来有效
看起来子线程在停止之前就终止了。但这只是运气。如果您扩大子线程所做的工作量,则不太可能发生这种情况。添加-a.stop();b.stop();a.start()之后;b.start();修复了问题
但我不明白为什么。欢迎来到stackoverflow。请直接将所有相关信息添加到您的帖子中,避免截图。您可能还需要检查。我不明白截图的意义。我也不明白发布两份100多行几乎相同的代码副本的意义……而不解释它们是如何产生的不同。您是否尝试加入线程?在a.start()
和b.start()
之后,您可以添加a.join()
和b.join()
确保它们在计算和之前都终止
第一个代码和第二个代码之间的区别是什么?这看起来像是一个非常标准的竞态条件,其中第一个、第二个和第三个使用的值根据两个线程是否完成执行而变化。我认为是指线程1中的count[0]
和线程2中的count[0]
之和是事件中所有0
s的数量:int first=a.count[0]+b.count[0]所以OP是正确的,所有0、所有1和所有2的总和应该是1000
。除非线程没有正确终止?但是,我不确定我是否理解这个问题如果你是正确的,错误的同步是>>他们甚至需要同步吗?Thread1处理“event”的前500个条目,查看值和计数递增。类似地,Thread2处理“event”的下500个条目,并在计数数组中递增。最后,我尝试添加两个计数数组。@StephenC另一个问题不是join
ing.1)这是一个随机的非修复程序。通过做出与真正的一个或多个错误无关的更改,很容易使多线程程序看起来正常工作。2)不要调用Thread。stop()
是不推荐的。因为当你到达它执行a.stop()
和b.stop()的行时
它很可能已经完成了执行。尽管正如Stephen C所提到的,这是随机的。假设您的线程a
需要10秒才能完成-但是您已经到达了行a.stop()
1秒后-然后它将强制停止,并且只完成10%。因此:这不是解决方案,而是随机的。