为什么使用Integer进行计算时会导致死锁?[复制]

why does it cause deadlock when I use Integer to computation? [duplicate]

提问人:JASON CHAN 提问时间:10/22/2023 最后编辑:Mark RotteveelJASON CHAN 更新时间:10/22/2023 访问量:50

问:

我正在尝试解决称为穿越单板桥的问题。以下是问题的描述:

有一座单板桥。只有一个人可以过桥 没有任何停止。行人可以从西边过桥 向东或从东向西。如果人行横道超过 0 个 这座桥从西向东,没有行人可以尝试过 从东到西的桥,但超过1名行人可以过桥 从西向东桥,反之亦然。行人可以过马路 如果桥上没有行人,请立即上桥。用 信号量来解决这个问题。

如果我使用 Integer,某个时候会发生死锁。当发生死锁时,wait semaphore、leftCnt 和 westCnt 的值为 0,但当 leftCnt 或 westCnt 等于零时,它会释放 wait 信号量。 但是,如果我使用 MyInt,一切都会顺利进行。

我的解决方案如下:

import java.util.concurrent.Semaphore;
//person from east to west
public class Task1 implements Runnable{
    Semaphore east, west, wait;
//    MyInt westCnt, eastCnt;
//    public Task1(Semaphore east, Semaphore west, Semaphore wait, MyInt westCnt, MyInt eastCnt) {
//        this.east = east;
//        this.west = west;
//        this.wait = wait;
//        this.westCnt = westCnt;
//        this.eastCnt = eastCnt;
//    }
    Integer westCnt, eastCnt;
    public Task1(Semaphore east, Semaphore west, Semaphore wait, Integer westCnt, Integer eastCnt) {
        this.east = east;
        this.west = west;
        this.wait = wait;
        this.westCnt = westCnt;
        this.eastCnt = eastCnt;
    }

    @Override
    public void run() {
        try {
            east.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        eastCnt.inc();
//        if(eastCnt.getInteger() == 1) {
//            try {
//                wait.acquire();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }

        eastCnt++;
        if(eastCnt.equals(1)) {
            try {
                wait.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("E -> W, on bridge");
        east.release();

        try {
            east.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("E -> W, finish");
//        eastCnt.dec();
//        if(eastCnt.getInteger() == 0)
//            wait.release();
        eastCnt--;
        if(eastCnt.equals(0))
            wait.release();
        east.release();
    }
}
import java.util.concurrent.Semaphore;
//person from west to east
public class Task2 implements Runnable{
    Semaphore east, west, wait;

//    MyInt westCnt, eastCnt;
//    public Task2(Semaphore east, Semaphore west, Semaphore wait, MyInt westCnt, MyInt eastCnt) {
//        this.east = east;
//        this.west = west;
//        this.wait = wait;
//        this.westCnt = westCnt;
//        this.eastCnt = eastCnt;
//    }
    Integer westCnt, eastCnt;
    public Task2(Semaphore east, Semaphore west, Semaphore wait, Integer westCnt, Integer eastCnt) {
        this.east = east;
        this.west = west;
        this.wait = wait;
        this.westCnt = westCnt;
        this.eastCnt = eastCnt;
    }
    @Override
    public void run() {
        try {
            west.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        westCnt.inc();
//        if(westCnt.getInteger() == 1) {
//            try {
//                wait.acquire();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
        westCnt++;
        if(westCnt.equals(1)) {
            try {
                wait.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("W -> E, on bridge");
        west.release();

        try {
            west.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("W -> E, finish");
//        westCnt.dec();
//        if (westCnt.getInteger() == 0)
//            wait.release();
        westCnt--;
        if(westCnt.equals(0))
            wait.release();
        west.release();
    }
}
//test
public class TestApplication {

    public static void main(String args[]) {
        Semaphore east = new Semaphore(1);
        Semaphore west = new Semaphore(1);
        Semaphore wait = new Semaphore(1);
//        MyInt eastInt = new MyInt();
//        MyInt westInt = new MyInt();
        Integer eastInt = 0;
        Integer westInt = 0;
        List<Thread> list1 = new ArrayList<>();
        List<Thread> list2 = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            list1.add(new Thread(new Task1(east,west,wait, eastInt, westInt)));
            list2.add(new Thread(new Task2(east,west,wait,eastInt, westInt)));
        }
        for (int i = 0; i < list1.size(); i++) {
            list1.get(i).start();
            list2.get(i).start();
        }
    }
}
public class MyInt {
    private int integer = 0;
    public void setInteger(int integer) {
        this.integer = integer;
    }

    public int getInteger() {
        return integer;
    }
    public void inc(){
        integer++;
    }

    public void dec(){
        integer--;
    }
}
Java 信号量

评论


答:

0赞 Elliott Frisch 10/22/2023 #1

Integer不可变的,因此每次值更改时,您都有一个不同的实例(根据定义)。使用 AtomicInteger 而不是重新发明它。

评论

0赞 JASON CHAN 10/22/2023
明白了。感谢您的回复。