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

Java 信号量实现的面向生产者-消费者的线程池,java,multithreading,threadpool,semaphore,producer-consumer,Java,Multithreading,Threadpool,Semaphore,Producer Consumer,我目前正在从事一项教育任务,其中我必须实现一个仅限信号量的线程安全线程池 我在分配任务期间不得使用:同步等待通知睡眠或任何线程安全API 首先,我没有过多地使用代码: 实现了一个线程安全队列(没有两个线程可以同时排队\dequeue)(我已经用ConcurrentLinkedQueue测试了这个问题,但问题仍然存在) 设计本身: 共享: 任务信号量=0 可用信号量=0 任务\u队列队列 可用队列队列 工作线程: 阻塞信号量=0 一般信息: 只有管理器(单线程)可以退出任务队列和可用

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

我在分配任务期间不得使用:
同步
等待
通知
睡眠
或任何线程安全API

首先,我没有过多地使用代码:

  • 实现了一个线程安全队列(没有两个线程可以同时排队\dequeue)(我已经用
    ConcurrentLinkedQueue
    测试了这个问题,但问题仍然存在)
设计本身:

共享:

  • 任务
    信号量=0

  • 可用
    信号量=0

  • 任务\u队列
    队列

  • 可用队列
    队列

工作线程:

  • 阻塞
    信号量=0
一般信息:

  • 只有管理器(单线程)可以退出
    任务队列
    可用队列

  • 只有App Main(单线程)可以将任务排入队列
    tasks\u Queue

  • 每个工作线程都可以在
    Available\u队列中排队

所以我们有一个单一的生产者,一个经理和几个消费者

  • 当应用程序第一次启动时,每个工作线程都会启动并立即在
    Available\u Queue
    中排队,释放
    Available
    信号量并被阻止获取其个人
    blocked
    信号量
  • 每当App Main将新任务排入队列时,它就会释放
    task
    Semaphore
  • 每当经理希望执行新任务时,必须首先获取
    任务
    可用
    信号量
我的问题:

在应用程序运行时,函数
dequeue\u worker()
返回一个空的worker,即使在已知没有可用的worker线程时放置了一个信号量来保护对队列的访问

我已经通过递归调用
dequeue\u 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();
    }
最后是Worker的
Run()
方法:

while (true) { // main infinite loop

                enqueue_worker(this);
                acquire(); // blocked.acquire();
                <C.S>
                available.release();
            }
while(true){//main无限循环
让工作人员排队(本);
acquire();//已阻止。acquire();
可用。释放();
}

您正在调用
available.release()
两次,一次在
让工作人员排队
,第二次在主循环中。

它的线程安全不阻塞。我的阻塞机制是通过
Available
Tasks
信号量实现的。您的递归迭代也执行相同的操作,但效率非常低。我想了解Available.acquire()调用空对象的.poll()是如何实现的。您调用了
Available.release()
两次,一次在
enqueue\u worker
中,第二次在大循环中我怎么会错过这个?!非常感谢你!请编辑您的答案,以反映这个捕获,我会选择是作为首选答案。