Multithreaded simple deadlock bug evading detection

时间:2016-04-12 00:46:19

标签: java multithreading deadlock

I am learning multithreading in class, so please no implemented solutions; improvement suggestions are appreciated though.

A 10,000 ft overview: main accepts 3 parameters (threads, resources, and runtime length). Each thread waits a random time, then decides to access the shared resources/critical section for a random time, upon completion relinquishing the resource. Repeat for provided runtime length, then exit all threads.

Based on the problem of users at a gocart track, taking turns riding and wandering around between rides.

I've created a deadlock, but I cannot find how that could be.

Sleeper just assigns the thread to wait for a time.

Rider class:

public void run() {
        while (!coord.exit) {
            System.out.format("Rider %d is gone walkabout%n", ID);
            Sleeper.walkAround(ID);
            System.out.format("Rider %d is in line%n", ID);
            try {
            carID = coord.getInLine();
            System.out.format("Rider %d is riding car %d%n", ID, carID);
            Sleeper.rideTime(ID);
            coord.returnCar(carID);
            } catch (InterruptedException ie) {System.out.println("Thread " + ID + " was interrupted.");}
        }
    }

The Coordinator class is where the meat is:

public class Coordinator {

    Rider[] riderArr;
    Semaphore mutex = new Semaphore(1);
    Semaphore cars;
    LinkedList<Integer> carLine;
    volatile static boolean exit = false;

    public synchronized int getInLine() throws InterruptedException {
        cars.acquire();
        mutex.acquire();
        int carid = carLine.removeFirst();
        mutex.release();
        return carid;
    }

    public synchronized void returnCar(int carID) throws InterruptedException {
        mutex.acquire();
        carLine.add(carID);
        mutex.release();
        cars.release();
    }

    public Coordinator(int cars, int riders) {
        riderArr = new Rider[riders];
        for (int i = 0; i < riders; i++) {
            riderArr[i] = new Rider(this, i + 1);
        }
        carLine = new LinkedList<Integer>();
        for (int i = 0; i < cars; i++) {
            carLine.add(i + 1);
        }
        this.cars = new Semaphore(cars);
    }

    public static void main(String[] args) throws NumberFormatException, InterruptedException {
        Coordinator coord = new Coordinator(Integer.parseInt(args[0]),
                Integer.parseInt(args[1]));
        for (int i = 0; i < Integer.parseInt(args[1]); i++) {
            coord.riderArr[i].start();
        }
        Thread.sleep(1000 * Integer.parseInt(args[2]));
        exit = true;
        for (int i = 0; i < Integer.parseInt(args[1]); i++) {
            coord.riderArr[i].join();
        }
        System.exit(0);
    }
}

Here is the console output for a deadlocked session:

Rider 2 is gone walkabout
Rider 2 is walking around for  4 seconds
Rider 1 is gone walkabout
Rider 1 is walking around for  1 seconds
Rider 1 is in line
Rider 1 is riding car 1
Rider 1 is riding for 3 seconds
Rider 2 is in line

1 个答案:

答案 0 :(得分:3)

这是一个死锁场景:

  • N个主题获取Semaphore
  • 中的所有N cars个令牌
  • 主题X输入getInLine并等待cars#acquire

因为getInLinesynchronized而X具有锁定,所以N个线程中的任何一个都无法返回令牌。这是因为returnCar方法也是synchronized

实现目标的更好方法是将carLine#removeFirstcarLine#add置于自己的synchronized方法中,并从其他两种方法中移除synchronized:< / p>

public synchronized int removeCar(){
    return carLine.removeFirst();
}

public synchronized void addCar(int car){
    carLine.add(car);
}

这也消除了对mutex对象的需求。您改为使用Coordinator对象本身作为互斥锁。这也意味着等待信号量上的acquire不会阻止你返回它的标记