【问题标题】:Suggest data-structure for this use case [closed]为这个用例建议数据结构[关闭]
【发布时间】:2017-06-29 17:12:56
【问题描述】:

语言:Java

我有一个固定的线程池在运行,所有的人都必须在某个时候提出问题并以(是/否)的形式接受用户输入,这基本上决定了它的进一步执行。由于我不想混合来自多个线程的输出问题,因此会有另一个任务/线程以固定速率运行(单个)(进一步称为主线程),可用于获取问题并将其显示给用户。线程提出的问题数量可能会有所不同,一旦问题得到答复,就不再需要它了。

此时我当前的实现使用LinkedTransferQueue,它基本上允许我在主线程和问题线程之间共享数据,而无需等待轮询。

我创建了一个Task 类的同步ArrayList,每个类都包含一个LinkedTransferQueue<String>。该线程创建一个新的Task 并使用transfer() 方法将其问题添加到其队列中。主线程拾取它们并从用户那里获得响应,然后将其放回同一个队列。这里的优点是LinkedTransferQueue 提供了take() 方法,让我无需轮询即可等待。

其他方法包括使用volatile shared 变量,其值由主线程更新,并不断被其他线程轮询。

请建议是否有任何其他数据结构可用于此类用例。据我所知,这不完全是生产者-消费者问题。如果您有任何其他疑虑,请发布问题。

谢谢!!

【问题讨论】:

  • 我不明白宽泛的原因。您能否证明一下,以便我可以处理以后的问题?我从 Andreas 那里得到了完全适合我的答案!

标签: java multithreading data-structures


【解决方案1】:

由于您希望线程等待答案,我建议创建一个问题对象,其中包含问题文本,可以存储答案,并有一个CountDownLatch 用于跟踪何时有答案。

public final class Question {
    private final String   question;
    private String         answer;
    private CountDownLatch latch = new CountDownLatch(1);

    public Question(String question) {
        this.question = question;
    }
    public String getQuestion() {
        return this.question;
    }
    public String getAnswer() throws InterruptedException {
        this.latch.await();
        return this.answer;
    }
    public void setAnswer(String answer) {
        this.answer = answer;
        this.latch.countDown();
    }
}

然后您的工作线程可以将该问题发送到主Queue,并等待答案,例如

public final class Worker implements Runnable {
    private final Queue<Question> queue;
    private final int             delayInSeconds;
    private final String[]        questions;

    public Worker(Queue<Question> queue, int delayInSeconds, String... questions) {
        this.queue = queue;
        this.delayInSeconds = delayInSeconds;
        this.questions = questions;
    }
    @Override
    public void run() {
        List<String> answers = new ArrayList<>();
        try {
            for (String question : this.questions) {
                Thread.sleep(this.delayInSeconds * 1000L);
                Question q = new Question(question);
                this.queue.add(q);
                String answer = q.getAnswer();
                answers.add(answer);
            }
        } catch (InterruptedException unused) {
            System.out.println("Interrupted");
        }
        System.out.println(answers);
    }
}

然后主线程将使用某种BlockingQueue 来等待问题,并一次处理一个问题,例如像这样:

public static void main(String[] args) throws Exception {
    BlockingQueue<Question> queue = new LinkedBlockingQueue<>();
    Worker w1 = new Worker(queue, 3, "Can you play poker?",
                                     "Can you juggle?",
                                     "Can you summersault?");
    Worker w2 = new Worker(queue, 4, "How old are you?",
                                     "How tall are you?");
    new Thread(w1).start();
    new Thread(w2).start();
    Scanner in = new Scanner(System.in); 
    for (int i = 0; i < 5; i++) {
        Question q = queue.take();
        System.out.println(q.getQuestion());
        String answer = in.nextLine();
        q.setAnswer(answer);
    }
}

样本输出

Can you play poker?
yes
How old are you?
13
Can you juggle?
no
How tall are you?
5 11
Can you summersault?
[13, 5 11]
no
[yes, no, no]

【讨论】:

  • CountDownLatch 是一种比我采用的更清洁的方法,无需连续轮询。太好了!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-21
  • 2015-01-05
  • 1970-01-01
  • 2014-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多