信号量实现的生产者 - 面向消费者的线程池

时间:2016-04-06 17:41:59

标签: java multithreading threadpool semaphore producer-consumer

我目前正在进行一项教育任务,我必须实现一个仅限信号量的线程安全线程池。

我在作业期间不得使用:Synchronize wait notify sleep或任何线程安全的API。

首先没有太多关注我的代码:

  • 实现了一个线程安全队列(没有两个线程可以同时排队\出队)(我已经用ConcurrentLinkedQueue测试了这个问题并且问题仍然存在)

设计本身:

共享:

  • Tasks信号量= 0

  • Available信号量= 0

  • Tasks_Queue队列

  • Available_Queue队列

工作人员主题:

  • Blocked信号量= 0

一般信息:

  • 只有经理(单线程)可以出列Tasks_QueueAvailable_Queue

  • 只有App-Main(单线程)可以排队任务Tasks_Queue

  • 每个工作线程都可以在Available_Queue

  • 中排队

所以我们混合了一个单一的生产者,一个经理和几个消费者。

  • 当应用程序首次启动时,每个工作线程都会启动并立即在Available_Queue中排队,释放Available信号量并被阻止获取它的个人Blocked信号量。
  • 每当App-Main将新任务排队时,它就会释放Task信号量
  • 每当Manager希望执行新任务时,它必须首先获得TasksAvailable信号量。

我的问题:

在应用程序的运行时期间,函数dequeue_worker()返回一个空工作符,即使知道没有可用的工作线程,也会放置一个信号量来保护对队列的访问。

我已经通过递归调用dequeue_worker()来解决问题,如果它绘制了一个空线程,但这样做是为了让获取信号量许可永久丢失。然而,当我将工人数量限制为1时,工人不会永远被阻止。

1)我的原创设计的突破点是什么?

2)为什么我的“解决方案”不能进一步打破设计?!

代码段:

// only gets called by Worker threads: enqueue_worker(this);
    private void enqueue_worker(Worker worker) {
       available_queue.add(worker);
       available.release();
    }

// only gets called by App-Main (a single thread)
    public void enqueue_task(Query query) {
        tasks_queue.add(query);
        tasks.release();
    }

// only gets called by Manager(a single Thread) 
    private Worker dequeue_worker() {
        Worker worker = null;
        try {
            available.acquire();
            worker = available_queue.poll();
        } catch (InterruptedException e) {
            // shouldn't happen
        } // **** the solution: ****
        if (worker==null) worker = dequeue_worker(); // TODO: find out why
        return worker;
    }

// only gets called by Manager(a single Thread) 
    private Query dequeue_task() {
        Query query = null;
        try {
            tasks.acquire();
            query = tasks_queue.poll();
        } catch (InterruptedException e) {
            // shouldn't happen
        } 
        return query;
    }

// gets called by Manager (a single thread)
    private void execute() { // check if task is available and executes it
        Worker worker = dequeue_worker(); // available.down()
        Query query = dequeue_task(); //task.down()
        worker.setData(query);
        worker.blocked.release();
    }

最后是工人的Run()方法:

while (true) { // main infinite loop

                enqueue_worker(this);
                acquire(); // blocked.acquire();
                <C.S>
                available.release();
            }

1 个答案:

答案 0 :(得分:3)

您正在available.release()两次,一次在enqueue_worker,第二次在主循环中。