具有大小受限资源池的多线程Java worker

时间:2016-01-28 01:22:11

标签: java multithreading synchronization thread-safety worker

我有这个'Worker'类,它使用资源'Client'。 可能有任意数量的线程,在任何给定时间运行'Worker'。 'Client'不是线程安全的,因此我使用'ThreadLocal'。 “客户端”连接到某个服务器并执行工作者为“客户端”提供的HTTP“请求”。

public class Worker {
// Client is NOT thread-safe !!! 
private static ThreadLocal<Client> client = new ThreadLocal<Client>();

@Override
protected void onGet(Request req) {
    handleRequest(req);
}

private void handleRequest(Request req) {
    someRunnableExecutor(new Runnable() {
        @Override
        public void run() {
            get_client().send_req(req);
        }
    });
}

private Client get_client() {
    Client c = client.get();
    if (c == null) {
       c = new Client();
       client.set(c);
    }
    return c;
}

在当前的实施(上图)中,为了清晰起见,有与“工人”一样多的“活跃”“客户”。

这是一个问题,因为服务器已经用尽。

我能做的只是修复'工人'。无法访问“客户”,服务器或运行工作程序的执行程序。

我想要做的是在“工作人员”中拥有一个“客户端”队列和一段同步代码,如果队列为空,则将“客户端”从队列中取出“工人”应该等到队列中有一个让他服用。然后将“客户端”放回队列中 - 同步。

我真的希望尽可能保持简单,尽可能对代码进行最小的更改。

没有新的类,没有工厂,只有一些数据结构来保存'客户端'和同步。

我对如何实现这一点感到有点困惑,以及“客户端”不是线程安全的事实,我必须'ThreadLocal'(ize)它。这是怎么把它放在队列中的?

private static Queue<ThreadLocal<CLient>> queue = 
      new LinkedList<ThreadLocal<CLient>>();

此外,我是如何/在何处使用5个客户端初始化该队列一次?

请分享您的想法。

1 个答案:

答案 0 :(得分:0)

这里不需要ThreadLocal,因为你想拥有的客户比工人少。你在BlockingQueue中所需要的一切。 注意!我认为客户端的send_req是同步的,如果不是 - 代码需要在run()方法中进行一些更改

public class Worker {

    private static final int CLIENTS_NUMBER = 5;
    private static final BlockingQueue<Client> queue = new LinkedBlockingQueue<>(CLIENTS_NUMBER);

    static {
        for (int i = 0; i < CLIENTS_NUMBER; i++)
            queue.put(new Client());
    }

    @Override
    protected void onGet(Request req) {
        handleRequest(req);
    }

    private void handleRequest(Request req) {
        someRunnableExecutor(new Runnable() {
            @Override
            public void run() {
                try {
                    Client client = takeClient();
                    client.send_req(req);
                    putClient(client);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
    }

    private Client takeClient() throws InterruptedException {
        return queue.take();
    }

    private void putClient(Client client) throws InterruptedException {
        queue.put(client);
    }
}