J'utilise un environnement multi-threadé, un thread est en constante écoute pour l'entrée de l'utilisateur en appelant à plusieurs reprises La fermeture du flux semble ne pas être une option depuis que je lise de Y a-t-il un moyen d'interrompre le blocage du scanner, de sorte qu'il reviendra? P>
merci p> scanner.nextline () code>.
Pour mettre fin à l'application, cette analyse est arrêtée par un autre thread, mais le thread d'écoute ne s'arrête pas jusqu'à ce qu'une dernière entrée de l'utilisateur ait été faite (en raison de la nature bloquante de
nextline () code>). P >
System.in code>, qui renvoie un
introuvable code> qui n'est pas resserrable. P>
3 Réponses :
Ce Article Décrit une approche pour éviter le blocage lors de la lecture. Il donne à l'extrait de code, que vous pourriez modifier comme je l'indique dans un commentaire. Vous pouvez utiliser ce code directement ou écrire une nouvelle classe d'introuvream fermée, en appuyant sur la logique décrite dans Cet article. P> p>
Hé merci, j'espérais une solution qui n'implique pas d'attente active.
Bien sûr. Utiliser un nuke. Appelez Le problème est que System.in est un flux d'entrée traditionnel avec blocage, et lorsqu'il bloque le thread est marqué comme en cours d'exécution. Vous ne pouvez pas l'interrompre. Donc, quel que soit le fil que vous utilisez pour lire le système.in appelle la lecture et la lecture bloquera le fil. Vous pouvez coaxer une partie de ces choses avec un tas d'astuces évitez de faire appel à la lecture sauf dans les cas où nous pouvons être sûrs qu'il n'y aura pas de bloc, puis constamment sonder. Mais, il n'y a pas de manière réelle autour du problème que toute tentative de lecture qui verrouille votre fil et aucune quantité de fermeture de flux sous-jacents ou n'interrompre ni l'arrêt du thread vous sauvera. Mais si vous meurez tout le VM ... le fil mourra. P>
Évidemment, vous devez vous assurer que le reste des threads est correctement sorti et que c'est juste qu'un stupide, je souhaite pouvoir répondre au fil d'entrée tapé qui est le dernier cintre. Mais, si c'est totalement le cas, la réponse correcte est de sortir, ou du moins au moins, la seule réponse qui fonctionnera sans brûler les cycles d'horlogerie sans raison et que le programme se termine. P> system.exit (0) code> à la fin de votre fil principal. Cela meurrera tout. Même le fil actif en attente dans le système.in. P>
J'ai effectivement essayé cela, et system.exit (0) code> n'a pas eu l'empêchait d'étonnamment. J'ai dû
tuer -9 code> le processus. Même
killall Java code> n'a pas fonctionné.
Cela a travaillé pour moi. Mais, malheureusement avec ce bug / échec, j'irais que cela pourrait bien être immunitaire Nuke.
Pour commencer avec: Cela ne résoudra pas le problème qui, pour fermer l'ensemble du programme, nécessite un appel système.exit () s'il y a eu une demande d'entrée non remplie (même si annulée). Vous pouvez potentiellement em> le contourner en surfant une frappe à une frappe dans la console, mais c'est un tout autre parc à balles. Si vous voulez le faire dans la console, est impossible à faire sans interrogation, car il est impossible de faire En réalité, non bloquer un fil en attente d'une entrée de System.in, comme système. À cause de cela, sans utiliser l'interrogation pour seulement demander une entrée si vous savez qu'il ne bloquera pas. P> Si vous voulez vraiment quelque chose qui agira comme une console interruptible () pour une console, vous devriez probablement examiner Faire une fenêtre de swing, ou similaire, et faire une simple interface d'entrée pour elle. Ce n'est pas vraiment difficile et aurait toutes les fonctionnalités que vous demandez, en dehors de certains cas de bord. P> Cependant, je travaillais moi-même, car je voulais un moyen pour un fil de fil Arrêtez d'attendre l'attente de l'entrée de System.in, sans fermer le programme (et tout en évitant le sondage), et c'est ce que j'ai proposé, avant de passer à ma propre fenêtre. P> Je ne peux pas dire avec aucun La confiance, c'est la meilleure pratique, mais il devrait être le fil-faire, semble aller bien fonctionner et je ne peux penser à aucun problème immédiat. Je voudrais basculer des échecs à partir de sorties alternatives (bien que, sinones non obsolètes), à des erreurs réelles. Vous pouvez annuler des demandes actives d'entrée soit en interrompant le thread, soit en appelant Annuler (), qui annule la demande d'attente actuellement. P> Il utilise des sémaphores et des threads pour créer une méthode NextLlline () qui peut être interrompu / annulé ailleurs. L'annulation n'est pas parfaite - vous ne pouvez annuler que la demande du fil d'attente, par exemple, mais l'interruption de threads doit fonctionner correctement. P> package testapp;
/**
*
* @author Devlin Grasley
*/
import java.util.concurrent.Semaphore;
import java.util.Scanner;
public class InterruptableSysIn {
protected static Scanner input = new Scanner (System.in);
protected static final Semaphore waitingForInput = new Semaphore(0,true); //If InterruptableSysIn is waiting on input.nextLine(); Can also be cleared by cancel();
protected static String currentLine = ""; //What the last scanned-in line is
private static final Input inputObject = new Input();
private static final Semaphore waitingOnOutput = new Semaphore (1); // If there's someone waiting for output. Used for thread safety
private static boolean canceled = false; //If the last input request was cancled.
private static boolean ignoreNextLine = false; //If the last cancel() call indicated input should skip the next line.
private static final String INTERRUPTED_ERROR = "\nInterrupted";
private static final String INUSE_ERROR = "\nInUse";
private static boolean lasLineInterrupted = false;
/**
* This method will block if someone else is already waiting on a next line.
* Gaurentees on fifo order - threads are paused, and enter a queue if the
* input is in use at the time of request, and will return in the order the
* requests were made
* @return The next line from System.in, or "\nInterrupted" if it's interrupted for any reason
*/
public static String nextLineBlocking(){
//Blocking portion
try{
waitingOnOutput.acquire(1);
}catch(InterruptedException iE){
return INTERRUPTED_ERROR;
}
String toReturn = getNextLine();
waitingOnOutput.release(1);
return toReturn;
}
/**
* This method will immediately return if someone else is already waiting on a next line.
* @return The next line from System.in, or
* "\nInterrupted" if it's interrupted for any reason
* "\nInUse" if the scanner is already in use
*/
public static String nextLineNonBlocking(){
//Failing-out portion
if(!waitingOnOutput.tryAcquire(1)){
return INUSE_ERROR;
}
String toReturn = getNextLine();
waitingOnOutput.release(1);
return toReturn;
}
/**
* This method will block if someone else is already waiting on a next line.
* Gaurentees on fifo order - threads are paused, and enter a queue if the
* input is in use at the time of request, and will return in the order the
* requests were made
* @param ignoreLastLineIfUnused If the last line was canceled or Interrupted, throw out that line, and wait for a new one.
* @return The next line from System.in, or "\nInterrupted" if it's interrupted for any reason
*/
public static String nextLineBlocking(boolean ignoreLastLineIfUnused){
ignoreNextLine = ignoreLastLineIfUnused;
return nextLineBlocking();
}
/**
* This method will fail if someone else is already waiting on a next line.
* @param ignoreLastLineIfUnused If the last line was canceled or Interrupted, throw out that line, and wait for a new one.
* @return The next line from System.in, or
* "\nInterrupted" if it's interrupted for any reason
* "\nInUse" if the scanner is already in use
*/
public static String nextLineNonBlocking(boolean ignoreLastLineIfUnused){
ignoreNextLine = ignoreLastLineIfUnused;
return nextLineNonBlocking();
}
private static String getNextLine(){
String toReturn = currentLine; //Cache the current line on the very off chance that some other code will run etween the next few lines
if(canceled){//If the last one was cancled
canceled = false;
//If there has not been a new line since the cancelation
if (toReturn.equalsIgnoreCase(INTERRUPTED_ERROR)){
//If the last request was cancled, and has not yet recieved an input
//wait for that input to finish
toReturn = waitForLineToFinish();
//If the request to finish the last line was interrupted
if(toReturn.equalsIgnoreCase(INTERRUPTED_ERROR)){
return INTERRUPTED_ERROR;
}
if(ignoreNextLine){
//If the last line is supposed to be thrown out, get a new one
ignoreNextLine = false;
//Request an input
toReturn = getLine();
}else{
return toReturn;
}
//If there has been a new line since cancelation
}else{
//If the last request was cancled, and has since recieved an input
try{
waitingForInput.acquire(1); //Remove the spare semaphore generated by having both cancel() and having input
}catch(InterruptedException iE){
return INTERRUPTED_ERROR;
}
if(ignoreNextLine){
ignoreNextLine = false;
//Request an input
toReturn = getLine();
}
//return the last input
return toReturn;
}
}else{
if(lasLineInterrupted){
//wait for that input to finish
toReturn = waitForLineToFinish();
//If the request to finish the last line was interrupted
if(toReturn.equalsIgnoreCase(INTERRUPTED_ERROR)){
return INTERRUPTED_ERROR;
}
//Should the read be thrown out?
if(ignoreNextLine){
//Request an input
toReturn = getLine();
}
}else{
ignoreNextLine = false; //If it's been set to true, but there's been no cancaleation, reset it.
//If the last request was not cancled, and has not yet recieved an input
//Request an input
toReturn = getLine();
}
}
return toReturn;
}
private static String getLine (){
Thread ct = new Thread(inputObject);
ct.start();
//Makes this cancelable
try{
waitingForInput.acquire(1); //Wait for the input
}catch(InterruptedException iE){
lasLineInterrupted = true;
return INTERRUPTED_ERROR;
}
if(canceled){
return INTERRUPTED_ERROR;
}
return currentLine;
}
public static String waitForLineToFinish(){
//If the last request was interrupted
//wait for the input to finish
try{
waitingForInput.acquire(1);
lasLineInterrupted = false;
canceled = false;
return currentLine;
}catch(InterruptedException iE){
lasLineInterrupted = true;
return INTERRUPTED_ERROR;
}
}
/**
* Cancels the currently waiting input request
*/
public static void cancel(){
if(!waitingOnOutput.tryAcquire(1)){ //If there is someone waiting on user input
canceled = true;
currentLine = INTERRUPTED_ERROR;
waitingForInput.release(1); //Let the blocked scanning threads continue, or restore the lock from tryAquire()
}else{
waitingOnOutput.release(1); //release the lock from tryAquire()
}
}
public static void cancel(boolean throwOutNextLine){
if(!waitingOnOutput.tryAcquire(1)){ //If there is someone waiting on user input
canceled = true;
currentLine = INTERRUPTED_ERROR;
ignoreNextLine = throwOutNextLine;
waitingForInput.release(1); //Let the blocked scanning threads continue
}else{
waitingOnOutput.release(1); //release the lock from tryAquire()
}
}
}
class Input implements Runnable{
@Override
public void run (){
InterruptableSysIn.currentLine = InterruptableSysIn.input.nextLine();
InterruptableSysIn.waitingForInput.release(1); //Let the main thread know input's been read
}
}
Vous pouvez appeler
scanner.hasnext () code> au lieu de
scanner.nextline () code> cette méthode mai b> bloc selon la Javadoc, vous pourriez donc avoir besoin de gérer cela. L'idée est que contrairement à
scanner.nextline () code>,
scanner.hasnext () code> Ne pas avancer l'entrée, vous pouvez donc vérifier un indicateur si le fil de lecture a été arrêté par Un autre fil avant d'appeler
scanner.nextline () code>
Oui, mais cela impliquerait un sondage constant.
Vous devriez pouvoir appeler le fil.Interrompt sur le thread d'écoute, cela entraînerait une introduction d'une interrupteIoException que vous pouvez obtenir de la méthode IoException (). Je ne sais pas comment il interagit avec NextLine () ou s'il fonctionne avec votre intrigue sous-jacente, mais il devrait terminer dans la plupart des cas.
@Josefx Selon mes tests, cela ne termine pas
Nextline code> - toujours. Au moins pas pour moi.