Группа потоков покидает поток зомби после вызова прерывания - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть поток супервизора и несколько рабочих потоков.Предположим, у нас есть эльфы, которые упаковывают подарки и отправляют их на фабрику, которая ставит их в очередь.После определенного количества подарков супервайзер приказывает прекратить работы.

Все мои рабочие потоки принадлежат группе потоков.Когда супервизор понимает, что необходимое количество подарков было достигнуто, он вызывает workerThreadGroup.interrupt ().Тем не менее, всегда остается работающий зомби, который продолжает производить.

Теперь, для некоторого кода:

public class Factory implements Runnable {

    @Override
    public void run() {
        createElves();
        startElves();

        while (goalNotAchieved) {
            orchestrator.awaitSupervisorTurn();
            System.out.println("Factory " + factoryID + " is working..");
            orchestrator.setWorkersTurn();


        }


        System.out.println("Factory " + factoryID + " FINISHED");
        joinElves();

    }


    private void joinElves() {
        for (int i = 0; i < numberOfElves; i++) {
            try {
                elvesThreads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void startElves() {
        for (int i = 0; i < numberOfElves; i++) {
            elvesThreads[i].start();
        }
    }

    private void createElves() {
        for (int i = 0; i < numberOfElves; i++) {
            IPosition elfPosition = positionBuilder.create(matrixSize, elfMap);
            ElfRunnable elfRunnable = elfBuilder.create(i, this, elfPosition,
                                                        orchestrator);
            elfMap.addEntry(elfRunnable, elfPosition);
            elfPosition.setOwner(elfRunnable);
            elvesThreads[i] = new Thread(elvesThreadGroup, elfRunnable);
        }
    }

    private synchronized void queryPositions() {
        try {
            positionQuerySemaphore.acquire();
            System.out.println("Factory " + factoryID + " starting query....");
            for (ElfRunnable elf : elves) {
                System.out.println("Queried " + elf + ": (" + elf.getElfPosition());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            positionQuerySemaphore.release();
        }

    }


    public synchronized void notifyGiftCreated(Gift gift) {
        if (producedGifts == maxGifts) {
            elvesThreadGroup.interrupt();
            goalNotAchieved = false;
            orchestrator.setWorkersTurn();
            System.out.println("Rejecting " + gift);

        } else {
            producedGifts++;
            System.out.println("GIFTS: " + producedGifts);
        }


    }

}


public class ElfRunnable implements Runnable {

    @Override
    public void run() {
        notifySupervisorFactory();
        while (threadIsAlive()) {

            orchestrator.awaitWorkersTurn();
            if (elfPosition.randomMove()) {
                Gift gift = new Gift(random.nextInt(), ID);
                orchestrator.setSuperVisorTurn();
                supervisorFactory.notifyGiftCreated(gift);
                rest();
            } else {
                awaitRandom();
            }


        }
        System.out.println("Elf " + ID + "/" + supervisorFactory + " is DONE");
    }

    private boolean threadIsAlive() {
        return !Thread.currentThread().isInterrupted();
    }


    private void notifySupervisorFactory() {
        supervisorFactory.becomeAware(this);
    }

    private void rest() {
        try {
            Thread.sleep(30);
        } catch (InterruptedException ignored) {
        }

    }

    private void awaitRandom() {

        int minimum = 10;
        int maximum = 50;
        int waitingTime = random.nextInt(maximum - minimum) + minimum;
        try {
            Thread.sleep(waitingTime);
        } catch (InterruptedException ignored) {
        }
    }


}


public class Orchestrator implements IDefinitions {
    private volatile int turn;

    public Orchestrator(int turn) {
        this.turn = turn;
    }

    public synchronized void awaitWorkersTurn() {
        while (turn == supervisorTurn) {
            try {
                wait();
            } catch (InterruptedException ignored) {
                return;
            }
        }
    }

    public synchronized void awaitSupervisorTurn() {
        while (turn == workerTurn ) {
            try {
                wait();
            } catch (InterruptedException ignored) {
                return;
            }
        }

    }

    public synchronized void setWorkersTurn() {
        turn = workerTurn;
        notifyAll();
    }

    public synchronized void setSuperVisorTurn() {
        turn = supervisorTurn;
        notifyAll();
    }



}

Теперь, что я получаю во время вывода:

Factory 0 got: 20 toys to produce, 347 as matrix size, 5 elves
Thread elf 0/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 1/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 2/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 3/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 4/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Factory 0 is working..
Elf 1 created a gift
Elf 3 created a gift
Elf 0 created a gift
Elf 4 created a gift
Elf 2 created a gift
Factory 0 is working..
GIFTS: 1
GIFTS: 2
GIFTS: 3
GIFTS: 4
GIFTS: 5
Elf 4 created a gift
Elf 2 created a gift
Elf 3 created a gift
Factory 0 is working..
GIFTS: 6
Elf 1 created a gift
Elf 0 created a gift
Factory 0 is working..
GIFTS: 7
GIFTS: 8
GIFTS: 9
GIFTS: 10
Elf 2 created a gift
GIFTS: 11
Elf 0 created a gift
GIFTS: 12
Elf 4 created a gift
Elf 3 created a gift
Factory 0 is working..
Elf 1 created a gift
GIFTS: 13
Factory 0 is working..
GIFTS: 14
GIFTS: 15
Elf 2 created a gift
Elf 4 created a gift
Elf 0 created a gift
Factory 0 is working..
GIFTS: 16
GIFTS: 17
GIFTS: 18
Elf 1 created a gift
Elf 3 created a gift
GIFTS: 19
Factory 0 is working..
GIFTS: 20
Elf 4 created a gift
Elf 0 created a gift
Elf 2 created a gift
Rejecting Gift--820046672-4
Factory 0 is working..
Elf 4/0 is DONE
Elf 1 created a gift
Elf 3 created a gift
----------------Factory 0 FINISHED----------------
Rejecting Gift-1775300653-2
Rejecting Gift--906406470-0
Elf 2/0 is DONE
Rejecting Gift--778562716-3
Elf 0/0 is DONE
Elf 3/0 is DONE
Rejecting Gift-912276334-1
Elf 1 created a gift
Rejecting Gift--203717575-1
Elf 1 created a gift
Rejecting Gift--504209300-1
Elf 1 created a gift
Rejecting Gift--1405618643-1
Elf 1 created a gift
Rejecting Gift-472265871-1
Elf 1 created a gift
Rejecting Gift-1573561986-1
Elf 1 created a gift
Rejecting Gift-2005222080-1
Elf 1 created a gift
Rejecting Gift-1722629349-1
Elf 1 created a gift
Rejecting Gift-678251744-1
Elf 1 created a gift
Rejecting Gift--1911462918-1
Elf 1 created a gift
Rejecting Gift-994905496-1
Elf 1 created a gift
Rejecting Gift--1700057698-1
Elf 1 created a gift
Rejecting Gift-2040969141-1
Elf 1 created a gift
Rejecting Gift--135605836-1
Elf 1 created a gift
Rejecting Gift--1320452586-1

Как видите, всегда работает один поток зомби.Почему это так?

1 Ответ

0 голосов
/ 03 декабря 2018

Проблема вашего кода в том, что вы хотите отменить / остановить ваши рабочие потоки с помощью метода interupt (), но в то же время вы вызываете методы в потоке, которые будут генерировать прерванное исключение, если поток уже прерван, иэто очистит статус прерывания.

Так, например, что может произойти в вашем коде:

ваш цикл метода запуска эльфа:

while (threadIsAlive()) {

1)           //dostuff -> while you are doing the stuff, supervisor call threadGroup.interrupt()
2)           awaitRandom();
}

1) во время вашего doStuffкод, супервизор вызывает threadGroup.interrupt () , это установит статус прерывания в вашем потоке, и если вы вызовите Thread.currentThread.isInterrupted (), вы получите true

2) здесь вывызывают метод sleep (), метод sleep будет выдавать InterruptedException , если он вызван в уже прерванном потоке, и он очистит состояние прерывания!проверьте javadoc: https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long), поэтому, если вы вызываете threadIsAlive () , метод Thread.currentThread.isInterrupted () вернет false.

Так чтовы можете сделать это, вы можете перехватить interrputedException в методе awaitRandom () (и во всех других методах, которые выдают InterruptedExceptions и очистить статус прерывания) и снова установить статус прерывания следующим образом:

 try {
            Thread.sleep(waitingTime);
        } catch (InterruptedException ex) {
    Thread.currentThread().interrupt(); //restores the interrupt status
}

Но гораздо лучшеопция заключается в том, чтобы отменить / остановить потоки с помощью другого механизма, отличного от флага прерывания.Вы можете ввести некоторую новую переменную остановки флага volatile в вашем рабочем потоке (аналогично тому, как это делается с goalNotAchtained), и вы можете установить эту переменную, если хотите отменить / остановить поток.

...