Sincronizzazione nei thread per Java
-
05-07-2019 - |
Domanda
Ho un server web cresciuto nella mia app. Questo web server genera un nuovo thread per ogni richiesta che arriva nel socket per essere accettata. Voglio che il web server aspetti fino a quando un punto specifico non viene raggiunto nel thread appena creato.
Ho passato molti post su questo sito ed esempi sul Web, ma non riesco a far procedere il server Web dopo che ho detto al thread di attendere. Un esempio di codice di base sarebbe fantastico.
La parola chiave sincronizzata è il modo corretto di procedere? In tal caso, come può essere raggiunto? Di seguito sono riportati esempi di codice della mia app:
Server Web
while (true) {
//block here until a connection request is made
socket = server_socket.accept();
try {
//create a new HTTPRequest object for every file request
HttpRequest request = new HttpRequest(socket, this);
//create a new thread for each request
Thread thread = new Thread(request);
//run the thread and have it return after complete
thread.run();
///////////////////////////////
wait here until notifed to proceed
///////////////////////////////
} catch (Exception e) {
e.printStackTrace(logFile);
}
}
Codice discussione
public void run() {
//code here
//notify web server to continue here
}
Aggiornamento: il codice finale è il seguente. Il HttpRequest
chiama semplicemente resumeListener.resume ()
ogni volta che invio un'intestazione di risposta (ovviamente aggiungendo anche l'interfaccia come classe separata e addResumeListener (ResumeListener r1 )
in HttpRequest
):
Parte del server Web
// server infinite loop
while (true) {
//block here until a connection request is made
socket = server_socket.accept();
try {
final Object locker = new Object();
//create a new HTTPRequest object for every file request
HttpRequest request = new HttpRequest(socket, this);
request.addResumeListener(new ResumeListener() {
public void resume() {
//get control of the lock and release the server
synchronized(locker) {
locker.notify();
}
}
});
synchronized(locker) {
//create a new thread for each request
Thread thread = new Thread(request);
//run the thread and have it return after complete
thread.start();
//tell this thread to wait until HttpRequest releases
//the server
locker.wait();
}
} catch (Exception e) {
e.printStackTrace(Session.logFile);
}
}
Soluzione
Prima di tutto, faccio eco al sentimento degli altri che reinventare la ruota qui porterà molto probabilmente a una serie di problemi per te. Tuttavia, se vuoi percorrere questa strada comunque, ciò che stai cercando di fare non è difficile. Hai sperimentato Jetty?
Forse qualcosa del genere:
public class MyWebServer {
public void foo() throws IOException {
while (true) {
//block here until a connection request is made
ServerSocket socket = new ServerSocket();
try {
final Object locker = new Object();
//create a new HTTPRequest object for every file request
MyRequest request = new MyRequest(socket);
request.addResumeListener(new ResumeListener() {
public void resume() {
locker.notify();
}
});
synchronized(locker){
//create a new thread for each request
Thread thread = new Thread(request);
//start() the thread - not run()
thread.start();
//this thread will block until the MyRequest run method calls resume
locker.wait();
}
} catch (Exception e) {
}
}
}
}
public interface ResumeListener {
public void resume();
}
public class MyRequest implements Runnable{
private ResumeListener resumeListener;
public MyRequest(ServerSocket socket) {
}
public void run() {
// do something
resumeListener.resume(); //notify server to continue accepting next request
}
public void addResumeListener(ResumeListener rl) {
this.resumeListener = rl;
}
}
Altri suggerimenti
Puoi utilizzare java.util.concurrent .CountDownLatch con un conteggio di 1 per questo. Predisporre che un'istanza di esso sia creata e condivisa dal thread padre e figlio (ad esempio, crearla nel costruttore di HttpRequest
e farlo recuperare da una funzione membro). Il server quindi chiama await ()
e il thread colpisce countDown ()
quando è pronto a rilasciare il suo genitore.
Probabilmente dovrai usare un Java Condizione . Dai documenti:
Condizioni (noto anche come condizione code o variabili di condizione) un mezzo per sospendere un thread esecuzione (per "attendere") fino alla notifica da un altro thread che alcuni stati la condizione potrebbe ora essere vera.
Esegui un debugger e imposta un punto di interruzione?
Se impossibile, leggi una riga da System.in?