Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
睡眠间隔导致问题的Java线程连接()_Java_Multithreading_Concurrency - Fatal编程技术网

睡眠间隔导致问题的Java线程连接()

睡眠间隔导致问题的Java线程连接(),java,multithreading,concurrency,Java,Multithreading,Concurrency,我正在做关于并发编程的教程,saw.join()方法用于确保线程在继续其余代码之前一直运行到完成 然而,当我尝试使用2线程来递增和递减一个变量,比如100倍(初始值:2000),最终结果应该显示2000,但它显示的是大于2000或小于2000。 当我在main方法中取消注释Thread.sleep时,它只能正常工作并始终显示2000 公共类主{ 公共静态void main(字符串[]args){ SharedObj SharedObj=新的SharedObj(); 螺纹1=新螺纹(新螺纹减去(s

我正在做关于并发编程的教程,saw.join()方法用于确保线程在继续其余代码之前一直运行到完成

然而,当我尝试使用2线程来递增和递减一个变量,比如100倍(初始值:2000),最终结果应该显示2000,但它显示的是大于2000或小于2000。 当我在main方法中取消注释
Thread.sleep
时,它只能正常工作并始终显示2000

公共类主{
公共静态void main(字符串[]args){
SharedObj SharedObj=新的SharedObj();
螺纹1=新螺纹(新螺纹减去(sharedObj));
螺纹2=新螺纹(新螺纹Plus(sharedObj));
thread1.start();
//试一试{
//睡眠(100);
//}catch(InterruptedException e){
//e.printStackTrace();
//        }
thread2.start();
试一试{
thread1.join();
螺纹2.连接();
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(“编号为:“+sharedObj.num”);
System.out.println(“增量计数:“+sharedObj.countPos”);
System.out.println(“减量计数:+sharedObj.countNeg”);
}
}
类SharedObj{
公共整数;
公共整数countPos=0;
公共整数countNeg=0;
公开股{
num=2000;
}
公共无效更改(int x){
num+=x;
if(x<0){
countNeg++;
}否则{
countPos++;
}
System.out.println(“编号为:+num+”,操作为:+x);
}
}
类thread减号实现可运行{
SharedObj SharedObj;
公共线程减号(SharedObj SharedObj){
this.sharedObj=sharedObj;
}
@凌驾
公开募捐{

对于(int i=1;i这不是导致问题的睡眠/连接。这是一种竞赛条件,即您在不保护同一变量的情况下递增该变量。将
synchronized
添加到SharedObj#change,您应该会很好:

public synchronized void change(int x) { //...
join()位于错误的位置

 public class ThreadJoinTest {
    public static void main(String[] args) throws InterruptedException {
        SharedObj sharedObj = new SharedObj();
        Thread thread1 = new Thread(new ThreadMinus(sharedObj));
        Thread thread2 = new Thread(new ThreadPlus(sharedObj));
        thread1.start();
        thread1.join();
//        try {
//            Thread.sleep(100);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        thread2.start();
        thread2.join();
//        try {
//            thread1.join();
//            thread2.join();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        System.out.println("number is: " + sharedObj.num);
        System.out.println("increment count: " + sharedObj.countPos);
        System.out.println("decrement count: " + sharedObj.countNeg);

    }
}

class SharedObj {
    public int num;
    public int countPos = 0;
    public int countNeg = 0;

    public SharedObj() {
        num = 2000;
    }

    public void change(int x) {
        num += x;
        if (x < 0) {
            countNeg++;
        } else {
            countPos++;
        }
        System.out.println("number is: " + num + " with operation: " + x);
    }
}

class ThreadMinus implements Runnable {
    SharedObj sharedObj;

    public ThreadMinus(SharedObj sharedObj) {
        this.sharedObj = sharedObj;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            sharedObj.change(-1);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class ThreadPlus implements Runnable {
    SharedObj sharedObj;

    public ThreadPlus(SharedObj sharedObj) {
        this.sharedObj = sharedObj;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            sharedObj.change(+1);
            try {
                Thread.sleep(50);`enter code here`
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
公共类ThreadJoinTest{
公共静态void main(字符串[]args)引发InterruptedException{
SharedObj SharedObj=新的SharedObj();
螺纹1=新螺纹(新螺纹减去(sharedObj));
螺纹2=新螺纹(新螺纹Plus(sharedObj));
thread1.start();
thread1.join();
//试一试{
//睡眠(100);
//}catch(InterruptedException e){
//e.printStackTrace();
//        }
thread2.start();
螺纹2.连接();
//试一试{
//thread1.join();
//螺纹2.连接();
//}catch(InterruptedException e){
//e.printStackTrace();
//        }
System.out.println(“编号为:“+sharedObj.num”);
System.out.println(“增量计数:“+sharedObj.countPos”);
System.out.println(“减量计数:+sharedObj.countNeg”);
}
}
类SharedObj{
公共整数;
公共整数countPos=0;
公共整数countNeg=0;
公开股{
num=2000;
}
公共无效更改(int x){
num+=x;
if(x<0){
countNeg++;
}否则{
countPos++;
}
System.out.println(“编号为:+num+”,操作为:+x);
}
}
类thread减号实现可运行{
SharedObj SharedObj;
公共线程减号(SharedObj SharedObj){
this.sharedObj=sharedObj;
}
@凌驾
公开募捐{

对于(int i=1;i之所以发生这种情况,是因为您试图同时更新同一变量的值。通过观察输出,您可以发现程序在某个时候由于这种并发性而无法更新值。您可以通过将方法“更改”设为“已同步”或增加每个线程在Main方法中保持睡眠。

您看到的问题是一个典型的竞争条件。 考虑<代码> num += x;< /c> >它看起来像是一个操作,但实际上它是CPU中的多个操作。

简单地说就是 1.temp1=num; 2.temp2=x; 3.temp3=temp1+temp2 4.num=temp3

它实际上发生在CPU的寄存器中,所以在编写Java时,您看不到它

当您有多个线程同时运行并且正在执行这些指令时,您可能会得到意外的结果

例如,让我们从x=1和num=2开始

线程A正在执行:

 1. temp1a = num; 
 2. temp2a = x; 
 3. temp3a = temp1a + temp2a; 
 4. num = temp3a; 
线程B正在执行

 1. temp1b = num;
 2. temp2b = x;
 3. temp3b = temp1b + temp2b;
 4. num = temp3b;
现在,如果他们同时执行这些操作,您可能会得到以下命令:

 1. temp1a = num; //2
 2. temp2a = x; //1
 3. temp3a = temp1a + temp2a; //3

 4. temp1b = num; //2
 5. temp2b = x; //1
 6. temp3b = temp1b + temp2b; //3
 7. num = temp3b; //3

 8. num = temp3a; //3
因此,尽管您将
num
增加了两次,但结果是3,而不是4。 这是一种竞争条件。有很多方法可以避免这种情况,同步是其中之一,但还有其他技术

如果你想更好地理解它,我真的推荐这门在线课程。

它非常便宜,你可以在几个小时内完成它,但它用例子很好地解释了这一点,完全是从头开始的,而且它可以并发地进入非常高级的主题。这是一个很好的时间投资

在您的情况下,只需像这样添加synchronized:

public synchronized void change(int x) {
    num += x;
    if (x < 0) {
        countNeg++;
    } else {
        countPos++;
    }
    System.out.println("number is: " + num + " with operation: " + x);
}
公共同步作废更改(int x){
num+=x;
if(x<0){
countNeg++;
}否则{
countPos++;
}
System.out.println(“编号为:+num+”,操作为:+x);
}
将解决问题,但这不是一个灵丹妙药。你应该花时间理解为什么它在这种情况下解决了问题,而在另一种情况下可能无法解决问题


我希望这会有所帮助。

这只会让线程一个接一个地执行,这与目的(并发性)背道而驰。是的,它将按顺序运行,而不是同时运行