Java中的多线程问题,运行时的结果不同
每当我运行这个程序,它都会给我不同的结果。有人能给我解释一下,或者给我一些我能找到答案的主题,以便理解代码中发生的事情吗Java中的多线程问题,运行时的结果不同,java,multithreading,multiprocessing,Java,Multithreading,Multiprocessing,每当我运行这个程序,它都会给我不同的结果。有人能给我解释一下,或者给我一些我能找到答案的主题,以便理解代码中发生的事情吗 class IntCell { private int n = 0; public int getN() {return n;} public void setN(int n) {this.n = n;} } public class Count extends Thread { static IntCell n = new IntCell(
class IntCell {
private int n = 0;
public int getN() {return n;}
public void setN(int n) {this.n = n;}
}
public class Count extends Thread {
static IntCell n = new IntCell();
public void run() {
int temp;
for (int i = 0; i < 200000; i++) {
temp = n.getN();
n.setN(temp + 1);
}
}
public static void main(String[] args) {
Count p = new Count();
Count q = new Count();
p.start();
q.start();
try { p.join(); q.join(); }
catch (InterruptedException e) { }
System.out.println("The value of n is " + n.getN());
}
}
class IntCell{
私有整数n=0;
public int getN(){return n;}
public void setN(int n){this.n=n;}
}
公共类计数扩展线程{
静态IntCell n=新的IntCell();
公开募捐{
内部温度;
对于(int i=0;i<200000;i++){
temp=n.getN();
n、 setN(温度+1);
}
}
公共静态void main(字符串[]args){
计数p=新计数();
计数q=新计数();
p、 start();
q、 start();
试试{p.join();q.join();}
捕获(中断异常e){}
System.out.println(“n的值是”+n.getN());
}
}
您正在并行运行两个线程,并通过这两个线程更新一个共享变量,这就是为什么您的答案总是不同的原因。像这样更新共享变量不是一个好的做法
要理解,您应该首先理解,然后用两个并发线程修改相同的数字n。如果Thread1读取n=2,则Thread2在Thread2写入增量之前读取n=2,Thread1将n增量为3,但Thread2将不再增量,而是将另一个“3”写入n。如果Thread1在Thread2读取之前完成增量,则两者都将增量 现在,两个线程都是并发的,您永远无法判断哪个线程将获得什么CPU周期。这取决于您的机器上还运行什么。因此,在上述覆盖情况下,您将始终丢失不同数量的增量
要解决这个问题,请通过n++在n上运行实增量。它们在单个CPU周期内运行。对
IntCell n
静态变量的访问在两个线程之间是并发的:
static IntCell n = new IntCell();
public void run() {
int temp;
for (int i = 0; i < 200000; i++) {
temp = n.getN();
n.setN(temp + 1);
}
}
static IntCell n=new IntCell();
公开募捐{
内部温度;
对于(int i=0;i<200000;i++){
temp=n.getN();
n、 setN(温度+1);
}
}
竞争条件使您在n.setN(temp+1)时无法有可预测的行为代码>的执行取决于之前调用的线程:temp=n.getN()代码>
如果它是当前线程,则您拥有该线程输入的值,否则您拥有另一个线程输入的最后一个值。
您可以添加同步机制以避免意外行为的问题。
原因很简单:您不会自动获取和修改计数器,从而使代码容易出现争用条件问题
下面是一个说明问题的示例:
线程1调用n.getN()
get0
线程2调用n.getN()
get0
线程1调用n.setN(1)
将n
设置为1
线程#2不知道线程#1已经将n
设置为1
,因此仍然调用n.setN(1)
将n
设置为1
,而不是您预期的2
,这称为竞争条件问题
最终结果将取决于执行代码时遇到的竞争条件问题的总量,这是不可预测的,因此它会从一个测试更改为另一个测试
修复它的一种方法是在synchronized
块中获取并设置计数器,以便像next一样以原子方式执行,实际上,它将强制线程在IntCell
的实例上获取分配给n
的独占锁,然后才能执行这段代码
synchronized (n) {
temp = n.getN();
n.setN(temp + 1);
}
输出:
The value of n is 400000
您也可以考虑使用java来代替计数器的代码> int >代码,以依赖于类型<代码> AddiDGET(int delta)< /> >或AdvutoDand()>代码>来增加您的计数器原子。
我想您需要从Java中的并发学习开始。这段代码看起来是为了产生随机结果而设计的;这是一个基本点,没有内存障碍,并发是不可预测的——这就是为什么它如此困难的原因。简而言之,解释这段代码为什么会产生随机答案不太可能对您有所帮助——您甚至需要在尝试编写并发代码之前进行更多的阅读。