简体   繁体   English

停止整个生产者和消费者线程并将控制权交给主线程

[英]Stop the whole producer and consumer threads and yield the control to main thread

DefaultRunners are producers and OrderTaker is a consumer DefaultRunners是生产者, OrderTaker是消费者

They both share a OrderQueue . 他们都共享OrderQueue

Currently, I use the variable isDone to indicate if a game is finished. 目前,我使用变量isDone来指示游戏是否完成。

Once each round is done, I want to make it repeat again and again. 每轮完成后,我想让它一次又一次地重复。

However, in my current implementation it will only run once. 但是,在我当前的实现中,它只运行一次。

How could I solve it? 我该怎么解决?

public class OrderQueue {

    public synchronized void pushOrder(Order order) throws InterruptedException {
        if (isDone) {
            wait();
        } else {
            runnersQueue.addLast(order);
            notifyAll();
        }
    }

    public void pullOrder() {
        try {
            if (runnersQueue.size() == 0) {
            } else if (isDone) {
                wait();
            } else {
                handleOrder(runnersQueue.pop());
            }
        } catch (InterruptedException e) {
    }

}

In my main class 在我的主要课堂上

while(true){
    enterYesToStart();
    DefaultRunners dfltRunner = new DefaultRunners(queue);
    OrderTaker taker = new OrderTaker(queue);
    taker.run();


    System.out.println("This round is finished"); # never reach to this line
}

Here's the full source code for the example 这是该示例的完整源代码

https://gist.github.com/poc7667/d98e3bf5b3b470fcb51e00d9a0d80931 https://gist.github.com/poc7667/d98e3bf5b3b470fcb51e00d9a0d80931

I've taken a look at your code snippets and the problem is fairly obvious. 我已经看了你的代码片段,问题很明显。 The main thread runs the OrderTaker runnable. 主线程运行OrderTaker runnable。 The main thread is stuck in an eternal loop as the while statement cannot complete unless it throws an exception. 主线程被卡在永久循环中,因为while语句无法完成,除非它抛出异常。 (Note that the same is true for your ThreadRunner runnable.) (请注意, ThreadRunner runnable也是如此。)

This means that the main thread i still pulling orders while the race is already done. 这意味着主线程我仍然在比赛已经完成时拉动订单。

The OrderTaker should exit it's while loop while once the race is done. 一旦比赛结束,OrderTaker应该退出它的while循环。 I guess that there are multiple ways achieve this, but one way is use a shared variable. 我想有多种方法可以实现这一点,但一种方法是使用共享变量。

I took your code and adapted it into a working example. 我拿了你的代码并将其改编成一个工作示例。

import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class RaceApp {

    public static void main(String[] args) throws InterruptedException {
        final RaceUpdateManager queue = new RaceUpdateManager();
        for (int i = 0; i < 3; i++) {
            queue.reset();
            List<Thread> threads = Arrays.asList(
                    new Thread(new Runner("Tortoise", 0, 10, queue)),
                    new Thread(new Runner("Hare", 90, 100, queue))
            );
            for (Thread thread : threads) {
                thread.start();
            }
            RaceUpdatesProcessor processor = new RaceUpdatesProcessor(queue);
            processor.run();
            System.out.println("Game finished");
        }
    }

    private static class RaceUpdateManager {
        private static final int TOTAL_DISTANCE = 300;

        //thread-safe implementation for queue so no external syncrhonization is required when adding/removing updates
        private final Deque<RaceUpdate> runnersQueue = new ConcurrentLinkedDeque<>();

        //lock used to sync changes to runnersRecords and done variables
        private final ReadWriteLock raceStatusLock = new ReentrantReadWriteLock();

        private final Map<String, Integer> runnersRecords = new HashMap<>();
        private volatile boolean raceDone = false;//volatile keyword guarantees visibility of changes to variables across threads

        public boolean isRaceDone() {
            return raceDone;
        }

        //updates can by added simultaneously (read lock)
        public void register(RaceUpdate raceUpdate) throws InterruptedException {
            Lock readLock = raceStatusLock.readLock();
            readLock.lock();
            try {
                if (!raceDone) {
                    runnersQueue.addLast(raceUpdate);
                }//ignore updates when the race is done
            } finally {
                readLock.unlock();
            }
        }

        //but they need to be processed in order (exclusive write lock)
        public void processOldestUpdate() {
            Lock writeLock = raceStatusLock.writeLock();
            writeLock.lock();
            try {
                RaceUpdate raceUpdate = runnersQueue.poll();
                if (raceUpdate != null) {
                    handleUpdate(raceUpdate);
                }
            } finally {
                writeLock.unlock();
            }
        }

        private void handleUpdate(RaceUpdate raceUpdate) {
            Integer distanceRun = runnersRecords.merge(
                    raceUpdate.runner, raceUpdate.distanceRunSinceLastUpdate, (total, increment) -> total + increment
            );

            System.out.printf("%s: %d\n", raceUpdate.runner, distanceRun);

            if (distanceRun >= TOTAL_DISTANCE) {
                raceDone = true;
                System.out.printf("Winner %s\n", raceUpdate.runner);
            }
        }

        public void reset() {
            Lock writeLock = raceStatusLock.writeLock();
            writeLock.lock();
            try {
                runnersQueue.clear();
                runnersRecords.clear();
                raceDone = false;
            } finally {
                writeLock.unlock();
            }
        }
    }

    public static class Runner implements Runnable {
        private final String name;
        private final int rest;
        private final int speed;
        private final RaceUpdateManager queue;
        private final Random rand = new Random();

        public Runner(String name, int rest, int speed, RaceUpdateManager queue) {
            this.name = name;
            this.rest = rest;
            this.speed = speed;
            this.queue = queue;
        }

        @Override
        public void run() {
            while (!queue.isRaceDone()) {
                try {
                    if (!takeRest()) {
                        queue.register(new RaceUpdate(this.name, this.speed));
                    }
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    //signal that thread was interrupted and exit method
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }

        private boolean takeRest() {
            return rand.nextInt(100) < rest;
        }
    }

    public static class RaceUpdatesProcessor implements Runnable {
        private final RaceUpdateManager queue;

        public RaceUpdatesProcessor(RaceUpdateManager queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            while (!queue.isRaceDone()) {
                try {
                    queue.processOldestUpdate();
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    //signal that thread was interrupted and exit method
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
    }

    public static class RaceUpdate {
        public final String runner;
        public final int distanceRunSinceLastUpdate;

        public RaceUpdate(String runner, int distanceRunSinceLastUpdate) {
            this.runner = runner;
            this.distanceRunSinceLastUpdate = distanceRunSinceLastUpdate;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM