Java 如何通知多线程应用程序中的特定线程

Java 如何通知多线程应用程序中的特定线程,java,multithreading,rest,sockets,servletcontextlistener,Java,Multithreading,Rest,Sockets,Servletcontextlistener,我正在开发一个服务器应用程序,它接收来自客户端的RESTful请求,并以新线程(UDP数据包)将其发送到特定设备。此外,它在执行开始时运行另一个由servlet侦听器启动的线程,该线程侦听从系统所有设备发送的UDP数据包 当客户端从特定设备发出请求时,REST服务必须启动一个线程,UDP数据包将从该线程发送到该设备,并等待响应。当UDP服务器最终从该设备接收到数据包时(从数据包检查ip),它必须通知被阻止的线程继续执行并完成 我曾考虑过使用wait()、notify()和notifyAll()方

我正在开发一个服务器应用程序,它接收来自客户端的RESTful请求,并以新线程(UDP数据包)将其发送到特定设备。此外,它在执行开始时运行另一个由servlet侦听器启动的线程,该线程侦听从系统所有设备发送的UDP数据包

当客户端从特定设备发出请求时,REST服务必须启动一个线程,UDP数据包将从该线程发送到该设备,并等待响应。当UDP服务器最终从该设备接收到数据包时(从数据包检查ip),它必须通知被阻止的线程继续执行并完成

我曾考虑过使用
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();
    }

}