首页 新闻 会员 周边

java 多线程实现加减交替运算 结果与预期不符

0
[已解决问题] 解决于 2019-08-13 17:33
package calc;

/**
 * @author : S K Y
 * @version :0.0.1
 */
class Resource {        //定义一个操作的资源
    private int num = 0;        //定义要进行加减操作的数据
    /*flag = true 表示可以进行加法操作,无法进行减法操作
     * flag = false 表示可以进行减法操作,无法进行加法操作*/
    private boolean flag = true;

    public synchronized void add() throws InterruptedException {
        if (!this.flag) {                 //现在需要执行的是减法操作,加法操作需要等待
            super.wait();
        }
        Thread.sleep(100);
        this.num++;
        System.out.println("[加法操作-" + Thread.currentThread().getName() + "]num = " + this.num+ " " + this.flag);
        this.flag = false;
        super.notifyAll();
    }

    public synchronized void sub() throws InterruptedException {
        if (this.flag) {            //现在进行的是减法操作,加法操作需要等待
            super.wait();
        }
        Thread.sleep(200);
        this.num--;
        System.out.println("[减法操作-" + Thread.currentThread().getName() + "]num = " + this.num + " " + this.flag);
        this.flag = true;
        super.notifyAll();
    }
}

class AddThread implements Runnable {
    private Resource resource;

    public AddThread(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            try {
                this.resource.add();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class SubThread implements Runnable {
    private Resource resource;

    public SubThread(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            try {
                this.resource.sub();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class MyCalculation {
    public static void main(String[] args) {
        Resource resource = new Resource();
        AddThread addThread = new AddThread(resource);
        SubThread subThread = new SubThread(resource);
        new Thread(addThread, "加法线程A").start();
        new Thread(addThread, "加法线程B").start();
        new Thread(subThread, "减法线程A").start();
        new Thread(subThread, "减法线程B").start();
    }
}

发现做最终运行结果如下:

[加法操作-加法线程A]num = 1 true
[减法操作-减法线程B]num = 0 false
[加法操作-加法线程B]num = 1 true
[减法操作-减法线程A]num = 0 false
[加法操作-加法线程A]num = 1 true
[减法操作-减法线程B]num = 0 false
[减法操作-减法线程A]num = -1 true
[加法操作-加法线程B]num = 0 true
[减法操作-减法线程A]num = -1 false
[减法操作-减法线程B]num = -2 true
[加法操作-加法线程A]num = -1 true
[减法操作-减法线程B]num = -2 false
[减法操作-减法线程A]num = -3 true
[加法操作-加法线程B]num = -2 true
[减法操作-减法线程A]num = -3 false
[减法操作-减法线程B]num = -4 true
[加法操作-加法线程A]num = -3 true
[减法操作-减法线程B]num = -4 false
[减法操作-减法线程A]num = -5 true
[加法操作-加法线程B]num = -4 true
[减法操作-减法线程A]num = -5 false

是什么原因会产生这样的现象呢?

灰色天空_graySky的主页 灰色天空_graySky | 菜鸟二级 | 园豆:202
提问于:2019-08-11 21:57
< >
分享
最佳答案
0

因为楼主没有讲自己这段代码的具体用途,所以我假设 楼主的目的是想 实现:
"先增加,后减少,没有增加就不会减少,即 num不会出现负数的情况"。
我觉得这段代码是实现不了这样的需求的,原因如下:
【假设减的线程sub1进入,因为flag=true,所以wait(),放弃了对象锁,但是sub1已经进入了方法体。
这时候sub2进入,因为flag=true,所以也wait()了,也放弃了对象锁,但是sub2也已经进入了方法体。
这个时候 加的线程 add1 来了,没人拿锁,所以add1成功拿到,并且进入了方法体。num++;之后 flag=false; 此时num=1; 这时候add1执行 notifyAll();
sub1和sub2 都被唤醒了,此时他们都进入了方法体,所以两者都会成功 -1,于是sub1和sub2之后 num = -1;】
所以出现了楼主跑出来的结果。

奖励园豆:5
Jinke2017 | 菜鸟二级 |园豆:237 | 2019-08-13 17:08

明白了,主要就是因为wait()之后释放了锁,导致两个相同职责的线程有机会都进去这个方法,然后挂起等待,当执行NotifyAll()后,就会造成连续执行相同方法的情况。感谢指点

灰色天空_graySky | 园豆:202 (菜鸟二级) | 2019-08-13 17:32
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册