Java 如何通知多线程应用程序中的特定线程
我正在开发一个服务器应用程序,它接收来自客户端的RESTful请求,并以新线程(UDP数据包)将其发送到特定设备。此外,它在执行开始时运行另一个由servlet侦听器启动的线程,该线程侦听从系统所有设备发送的UDP数据包 当客户端从特定设备发出请求时,REST服务必须启动一个线程,UDP数据包将从该线程发送到该设备,并等待响应。当UDP服务器最终从该设备接收到数据包时(从数据包检查ip),它必须通知被阻止的线程继续执行并完成 我曾考虑过使用Java 如何通知多线程应用程序中的特定线程,java,multithreading,rest,sockets,servletcontextlistener,Java,Multithreading,Rest,Sockets,Servletcontextlistener,我正在开发一个服务器应用程序,它接收来自客户端的RESTful请求,并以新线程(UDP数据包)将其发送到特定设备。此外,它在执行开始时运行另一个由servlet侦听器启动的线程,该线程侦听从系统所有设备发送的UDP数据包 当客户端从特定设备发出请求时,REST服务必须启动一个线程,UDP数据包将从该线程发送到该设备,并等待响应。当UDP服务器最终从该设备接收到数据包时(从数据包检查ip),它必须通知被阻止的线程继续执行并完成 我曾考虑过使用wait()、notify()和notifyAll()方
wait()
、notify()
和notifyAll()
方法,但是,由于许多线程可能会在等待多个设备的响应时被阻塞,我看不出如何通知仅解锁所需的线程(在响应设备上发出请求的线程)。有没有一种方法可以使用这种方法来实现这一点?还有别的办法吗?以下是一些代码(简化):
SocketServletListener:
public class SocketServletListener implements ServletContextListener {
private UDPServer server;
private ServletContext context;
@Override
public void contextInitialized(ServletContextEvent sce) {
context = sce.getServletContext();
server = new UDPServer();
server.start();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
context = sce.getServletContext();
server.interrupt();
}
}
UDPServer:
public class UDPServer extends Thread {
private SocketUDPCommunication comm;
public UDPServer() {
comm = new SocketUDPCommunication();
}
@Override
public void run() {
DatagramPacket response;
try {
comm.setPort(Utils.UDP_SERVER_PORT);
comm.createSocket();
while (!Thread.currentThread().isInterrupted()) {
try {
response = comm.receiveResponse();
} catch (SocketTimeoutException e) {
continue;
}
InetAddress ip = response.getAddress();
int port = response.getPort();
byte[] byteSend = comm.discardOffset(response);
//TODO notify thread which made the request for the responding device (identified by ip)
}
} catch (IOException e) {
System.err.println("Unable to process client request: " + e.getMessage());
} catch (IllegalArgumentException ex) {
System.err.println("Illegal Argument: " + ex.getMessage());
} finally {
comm.closeConnection();
}
}
@Override
public void interrupt() {
super.interrupt();
comm.closeConnection();
}
}
DataSend.java:
@Path("dataSend")
public class DataSend {
@Context
private UriInfo context;
public DataSend() {
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response postJson(ForceStatus status) {
new TestExecution(status).start();
return Response.status(Response.Status.OK).build();
}
}
测试执行:
public class TestExecution extends Thread {
private ForceStatus status;
public ExamExecution(ForceStatus status) {
this.status = status;
}
@Override
public void run() {
ProtocolStatus p = new ProtocolStatus();
byte[] s = p.createResponseFrame(status.getForce());
List<Integer> executedTest = new ArrayList<>();
//Simple UDP client
UDPClient client = new UDPClient();
.
.
.
//t is a pojo which contains the data from a battery of tests
while(!executedTest.contains(t.getTestId())) {
client.send(status.getIp(), status.getPort(), s);
//TODO wait until UDPServer thread gets the response from the device
executedTest.add(t.getTestId());
nextTest = t.getNextTestId();
t = getEntity(nextTest);
}
}
}
公共类TestExecution扩展线程{
私人地位;
公开考试执行(强制状态){
这个状态=状态;
}
@凌驾
公开募捐{
ProtocolStatus p=新的ProtocolStatus();
字节[]s=p.createResponseName(status.getForce());
List executedTest=新建ArrayList();
//简单UDP客户端
UDPClient client=新的UDPClient();
.
.
.
//t是一个pojo,其中包含来自一组测试的数据
而(!executedTest.contains(t.getTestId())){
send(status.getIp(),status.getPort(),s);
//TODO等待,直到UDPServer线程从设备获取响应
add(t.getTestId());
nextestt=t.getnextestid();
t=获取实体(nextTest);
}
}
}
我是这样解决的:
首先,我创建了一个singleton类来管理由不同线程共享的请求列表
public class SharedWaitingThreads {
private ArrayList<ResponseToWait> queue;
private static SharedWaitingThreads mySharedWaitingThreads;
private SharedWaitingThreads() {
queue = new ArrayList<>();
}
public static SharedWaitingThreads getInstance() {
if(mySharedWaitingThreads == null)
mySharedWaitingThreads = new SharedWaitingThreads();
return mySharedWaitingThreads;
}
public ArrayList<ResponseToWait> getQueue() {
return queue;
}
public void setQueue(ArrayList<ResponseToWait> queue) {
this.queue = queue;
}
public void waitForAnswer(ResponseToWait r) throws InterruptedException {
System.out.println("Petición registrada " + r.toString());
synchronized(mySharedWaitingThreads) {
mySharedWaitingThreads.getQueue().add(r);
while(mySharedWaitingThreads.getQueue().contains(r)) {
mySharedWaitingThreads.wait();
}
}
}
public ResponseToWait answerWaitingThread(ResponseToWait r, boolean compareSeqNum) {
ResponseToWait rw = null;
synchronized(mySharedWaitingThreads) {
for(ResponseToWait rwAux : mySharedWaitingThreads.getQueue()) {
if(rwAux.equals(r)) {
rw = rwAux;
mySharedWaitingThreads.getQueue().remove(rwAux);
//every time a thread is released, notify to release the lock
mySharedWaitingThreads.notifyAll();
break;
}
}
}
return rw;
}
}
udp服务器线程必须根据收到的响应,回答等待线程的具体问题:
public class UDPServer extends Thread {
private SocketUDPCommunication comm;
private UDPClient udpClient;
private SharedWaitingThreads waitingThreads;
public UDPServer(SharedWaitingThreads waitingThreads) {
comm = new SocketUDPCommunication();
udpClient = new UDPClient();
this.waitingThreads = waitingThreads;
}
@Override
public void run() {
DatagramPacket response;
try {
comm.setPort(Utils.UDP_SERVER_PORT);
comm.createSocket();
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Waiting for clients to connect on port:" + comm.getSocket().getLocalPort());
try {
response = comm.receiveResponse();
} catch (SocketTimeoutException e) {
continue;
}
InetAddress ip = response.getAddress();
int port = response.getPort();
byte[] byteSend = comm.discardOffset(response);
byte[] header = new byte[Utils.STD_HEADER_SIZE];
Utils.getCleanHeader(byteSend, header);
byte type = header[12];
ResponseToWait r1;
if(type == Utils.TYPE_CONFIG_REPORT) {
ProtocolConfig pc = new ProtocolConfig();
pc.parseFrame(byteSend);
int mapType = pc.getPayload()[0];
int idElement = pc.getPayload()[1];
r1 = new ResponseToWait(ip.getHostAddress(), port, Utils.TYPE_CONFIG, null);
if(checkPendingRequests(r1, null)) {
System.out.println("Resending config");
continue;
}
waitingThreads.answerWaitingThread(r1, true);
}else if(type == Utils.TYPE_STATUS_REPORT) {
ProtocolStatus protocol = new ProtocolStatus();
r1 = new ResponseToWait(ip.getHostAddress(), port, Utils.TYPE_STATUS);
if(checkPendingRequests(r1, statusTest)) continue;
byte[] frame;
if(statusTest.equals(StatusTest.FINALIZED)) {
System.out.println("Test finalized. Waking threads");
r1 = new ResponseToWait(ip.getHostAddress(), port, Utils.TYPE_STATUS, null);
//Free possible waiting threads
ResponseToWait res1 = waitingThreads.answerWaitingThread(r1, false);
}
}
}
} catch (IOException e) {
System.err.println("Unable to process client request: " + e.getMessage());
} catch (IllegalArgumentException ex) {
System.err.println("Illegal Argument: " + ex.getMessage());
} catch (InterruptedException ex) {
Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, ex);
} finally {
comm.closeConnection();
}
}
private boolean checkPendingRequests(ResponseToWait rw, StatusTest status) {
boolean resend = false;
System.out.println("Status: " + status);
synchronized(waitingThreads) {
for(ResponseToWait r : waitingThreads.getQueue()) {
if(r.getResponseType() == Utils.TYPE_CONFIG && r.getIp().equals(rw.getIp())) {
udpClient.send(r.getIp(), r.getPort(), r.getFrame());
resend = true;
}
if(r.getResponseType() == Utils.TYPE_STATUS && r.getIp().equals(rw.getIp())){
udpClient.send(r.getIp(), r.getPort(), r.getFrame());
resend = true;
}
}
}
return resend;
}
@Override
public void interrupt() {
super.interrupt();
comm.closeConnection();
}
}
请注意,我简化了代码,试图使其更简单、更具说教性,实际情况更复杂?你应该看看,它有你的答案可能与我的答案相同。我建议使用类似Netty的东西,而不是自己尝试构建这种东西。我的情况不一样,因为我必须只解锁被服务器收到响应的客户端线程请求阻塞的线程,而不是所有线程
public class UDPServer extends Thread {
private SocketUDPCommunication comm;
private UDPClient udpClient;
private SharedWaitingThreads waitingThreads;
public UDPServer(SharedWaitingThreads waitingThreads) {
comm = new SocketUDPCommunication();
udpClient = new UDPClient();
this.waitingThreads = waitingThreads;
}
@Override
public void run() {
DatagramPacket response;
try {
comm.setPort(Utils.UDP_SERVER_PORT);
comm.createSocket();
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Waiting for clients to connect on port:" + comm.getSocket().getLocalPort());
try {
response = comm.receiveResponse();
} catch (SocketTimeoutException e) {
continue;
}
InetAddress ip = response.getAddress();
int port = response.getPort();
byte[] byteSend = comm.discardOffset(response);
byte[] header = new byte[Utils.STD_HEADER_SIZE];
Utils.getCleanHeader(byteSend, header);
byte type = header[12];
ResponseToWait r1;
if(type == Utils.TYPE_CONFIG_REPORT) {
ProtocolConfig pc = new ProtocolConfig();
pc.parseFrame(byteSend);
int mapType = pc.getPayload()[0];
int idElement = pc.getPayload()[1];
r1 = new ResponseToWait(ip.getHostAddress(), port, Utils.TYPE_CONFIG, null);
if(checkPendingRequests(r1, null)) {
System.out.println("Resending config");
continue;
}
waitingThreads.answerWaitingThread(r1, true);
}else if(type == Utils.TYPE_STATUS_REPORT) {
ProtocolStatus protocol = new ProtocolStatus();
r1 = new ResponseToWait(ip.getHostAddress(), port, Utils.TYPE_STATUS);
if(checkPendingRequests(r1, statusTest)) continue;
byte[] frame;
if(statusTest.equals(StatusTest.FINALIZED)) {
System.out.println("Test finalized. Waking threads");
r1 = new ResponseToWait(ip.getHostAddress(), port, Utils.TYPE_STATUS, null);
//Free possible waiting threads
ResponseToWait res1 = waitingThreads.answerWaitingThread(r1, false);
}
}
}
} catch (IOException e) {
System.err.println("Unable to process client request: " + e.getMessage());
} catch (IllegalArgumentException ex) {
System.err.println("Illegal Argument: " + ex.getMessage());
} catch (InterruptedException ex) {
Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, ex);
} finally {
comm.closeConnection();
}
}
private boolean checkPendingRequests(ResponseToWait rw, StatusTest status) {
boolean resend = false;
System.out.println("Status: " + status);
synchronized(waitingThreads) {
for(ResponseToWait r : waitingThreads.getQueue()) {
if(r.getResponseType() == Utils.TYPE_CONFIG && r.getIp().equals(rw.getIp())) {
udpClient.send(r.getIp(), r.getPort(), r.getFrame());
resend = true;
}
if(r.getResponseType() == Utils.TYPE_STATUS && r.getIp().equals(rw.getIp())){
udpClient.send(r.getIp(), r.getPort(), r.getFrame());
resend = true;
}
}
}
return resend;
}
@Override
public void interrupt() {
super.interrupt();
comm.closeConnection();
}
}