我有这个'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个客户端初始化该队列一次?
请分享您的想法。
答案 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);
}
}