扫描仪(System.in) - 如何取消/跳过输入等待 [英] Scanner(System.in) - how to cancel/skip input waiting

查看:176
本文介绍了扫描仪(System.in) - 如何取消/跳过输入等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是想知道如何在单独的线程中控制控制台输入?

我有线程A和线程B和线程C; B和C他们都控制用户输入...事情是我不太确定如何在B和C线程之间切换 scanIn.nextLine(); 因为B似乎在线程C可以中断B之前循环两次不必要的迭代:(

I am just wondering how to control console inputs in separate threads?
I have thread A and thread B and thread C; B and C they both control user input... the thing is I am not pretty sure how to switch between B and C threads the scanIn.nextLine(); because B seems to loop two unnecessary iterations before thread C can interrupt B :(

主线程:

  public class Main
        {
            private volatile ThreadGroup threadGroup=new ThreadGroup();//contains concurrent hash map...
            private volatile TaskManager taskManager=new TaskManager(threadGroup);
            private A a=new A(threadGroup);
            private B b=new B(threadGroup,taskManager);
            private C c=new C(threadGroup);


     Main()
    {

      b.start();

      threadGroup.add(a,"A");
      threadGroup.add(b,"B");
      threadGroup.add(c,"C");
    }

    public static void main(String args[]){new Main();}

        }

任务经理方法片段:

...
public synchronized void threadCMaybeCanBeStartedLater()
{
      this.getThreadGroup().get("A").start(); 
}
...

线程像一样的代码(重写的run方法调用)

public void loopIt()
{
   Random generator = new Random(); 
   A: while(!this.interrupted())
{
   Thread.sleep(1000);

   int i=generator.nextInt(100)+1;
   int j=generator.nextInt(100)+1;
   if(i==j){this.invokeC(); System.out.println("event : i==j");}

    }
 }

private void invokeC()
{
  if(!this.getThreadGroup().get("C").isAlive())this.getThreadGroup().get("C").start(); 
}

线程B代码如下:

public void loopIt() throws InterruptedException
    {


        Scanner scanIn = new Scanner(System.in);

        B: while(!this.isInterrupted())
        {

            Thread.sleep(1000);

            String command= scanIn.nextLine();
...

         if(command.equals("a"))
        {   
            System.out.println("a was entered");
            this.getTaskManager().threadCMaybeCanBeStartedLater();//             
            continue;
        }
        if(command.equals("b"))
        {   
           System.out.println("b was entered");            
           continue;
        }
        if(command.equals("c"))
        {
            System.out.println("c was entered");
            continue;
        }
        else{System.out.println("no such command");}

    }

}

线程C (运行方法调用)

public void loopIt() throws InterruptedException
        {
            getThreadGroup().get("B").interrupt();

            Scanner scanIn = new Scanner(System.in);

            C: while(!this.isInterrupted())
            {

                Thread.sleep(1000);

                String command= scanIn.nextLine();
    ...

             if(command.equals("d"))
            {   
                System.out.println("d was entered");             
                continue;
            }
            if(command.equals("e"))
            {   
               System.out.println("e was entered");            
               this.interrupt();
               break C;
            }
            if(command.equals("f"))
            {
                System.out.println("f was entered");
                continue;
            }
            else{System.out.println("no such command");}

        }

       getThreadGroup().get("B").start();

    }

...如您所见,主要代码概念(参见一个线程片段)是你不知道什么时候可以启动线程C但是当它启动时你需要给它控制台;就这样;如果它是GUI没有问题,但类似控制台的应用程序使它很成问题...

...as you can see, the major code conception (see A thread snippet) is "you don't know when thread C can be started but when it started you need to give it console"; that's all; if it was GUI there was no problem but console-like app makes it quite problematic...

所以问题是......如何中断/重新启动线程在这种情况下,B立即从线程C?

So the question is ... how to interrupt/re-start thread B immediately from thread C in this case?

谢谢

推荐答案

使用线程类同步线程


  1. Thread.interrupt()本身不会同步逻辑&两个线程之间的时间

  1. Thread.interrupt() on its own does not synchronise logic & timing between two threads.

Thread.interrupt()表示调用者喜欢线程在近处中断未来。 interrupt()方法设置一个中断标志。 isInterrupted()方法检查是否设置了此标志(&也再次清除该标志)。方法Thread.sleep(),Thread.join(),Object.wait()和许多I / O方法也检查&抛出InterruptedException时清除此标志。

Thread.interrupt() signals that the caller would like the thread to interrupt at a time in the near future. The interrupt() method sets an interrupt flag. The isInterrupted() method checks whether this flag is set (& also clears the flag again). The methods Thread.sleep(), Thread.join(), Object.wait() and a number of I/O methods also check & clear this flag, when throwing InterruptedException.

线程不会立即暂停但继续运行代码。内部线程逻辑设计&由开发人员实现:继续运行被认为是原子/紧急的线程代码,直到它达到可中断点,然后检查中断的标志/捕获InterruptedException&然后做一个干净的暂停 - 通常是通过 Thread.sleep() Thread.join() Object.wait(),有时通过完全退出 Thread.run(),从而永久停止线程。

The thread doesn't immediately pause but continues running code. The internal thread logic is designed & implemented by the developer: continue to run thread code considered atomic/urgent until it gets to an "interruptable point", then check the interrupted flag / catch InterruptedException & then do a clean pause - usually via Thread.sleep(), Thread.join() or Object.wait(), and sometimes by exiting Thread.run() altogether thus stopping the thread permanently.

当所有这一切都发生时,调用线程仍在运行,并且在中断生效之前将执行不确定数量的代码...因此缺乏同步。一个线程中的代码与另一个线程中的代码之间缺乏保证发生前的条件

While all of this is happening the calling thread is still running and will execute an indeterminate amount of code before the interrupt takes effect... hence the lack of synchronisation. There is a lack of guaranteed happens-before condition between the code in one thread and code in the other thread.

一些方法同步逻辑&两个线程之间的时间间隔(创建发生前的条件):

Some approaches that do synchronise logic & timing between two threads (creating a happens-before condition):


  • thread1调用Thread2.join ()

  • thread1 calls Thread2.join()

thread1调用SomeObject.wait()和thread2调用SomeObject.notify()

thread1 calls SomeObject.wait() and thread2 calls SomeObject.notify()

同步方法或块

快速审查您的代码:


  1. 线程B以无限循环运行 - 没有任何调用可以从任何循环中断它线程并没有调用它的线程等待()。然而,它会暂时阻塞,直到System.in有更多输入,然后继续。

  2. 线程A只会自行中断 - 如果不调用<$,则更清晰,更容易分析逻辑c $ c> this.interrupt()和 while(!this.isInterrupted()):只需将while循环更改为: do {....} while(i!= j)

  3. 线程A只会中断自身 - 更清晰,更容易分析逻辑如果你不要调用 this.interrupt() while(!this.isInterrupted()):只需更改while循环进入:做{....} while(!e.equals(command))

  4. 线程C必须在while循环的顶部进行以下调用:

  1. Thread B runs in an infinite loop - there is no call to interrupt it from any thread and no call for it's thread to wait(). It will, however, temporily block until System.in has more input, and then continue.
  2. Thread A only interrupts itself - cleaner and easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (i != j)
  3. Thread A only interrupts itself - cleaner and much easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (!"e".equals(command))
  4. Thread C must make the following calls at the top of it's while loop:

 threadB.interrupt();
 synchronized(this) {
     try {
         this.wait();
     } catch (InterruptedException ie) {
     }


  • 线程B必须将以下调用作为最后一行代码:

  • Thread B must make the following call as the last line of code:

     synchronized(threadC) {
             threadC.notify();
     }
    


  • 从I / O读取( nextLine ())是阻止&可中断的操作。在它旁边你介绍 Thread.sleep()这也是一个阻塞&可中断的操作会在代码中引入人为延迟 - 这是不必要的;删除。

  • Reading from I/O (nextLine()) is a blocking & interruptable operation. Right next to it you introduce Thread.sleep() which is also a blocking & interruptable operation that introduces an artificial delay in your code - it is not necessary; remove.

    建议更改:

    public class ThreadA extends Thread {
    
        ThreadC threadC;
    
        public void setThreadC(ThreadC threadC) {
            this.threadC = threadC;
        }
    
        @Override
        public void run() {
            this.loopIt();
        }
    
        public void loopIt() {
            Random generator = new Random(); 
            int i, j;
            do {
                try { 
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {                
                }
                i=generator.nextInt(100)+1;
                j=generator.nextInt(100)+1;
            } while (i != j);
            threadC.start();
        }
    
    }
    public class ThreadB extends Thread {
    
        ThreadA threadA;
        ThreadC threadC;
    
        public void setThreadA(ThreadA threadA) {
            this.threadA = threadA;
        }
        public void setThreadC(ThreadC threadC) {
            this.threadC = threadC;
        }
    
        @Override
        public void run() {
            this.loopIt();
        }
    
        public void loopIt() {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String command = null;
            // loop until interrupted
            try {
                while (!this.isInterrupted()) {
                    command = reader.readLine();
                    if ("a".equals(command)) {   
                        System.out.println("a was entered");
                        if (threadA.getState() == Thread.State.NEW) {
                            threadA.start();
                        }
                    } else if ("b".equals(command)) {   
                        System.out.println("b was entered");            
                    } else if ("c".equals(command)) {
                        System.out.println("c was entered");
                    } else if ("z".equals(command)) {
                        System.out.println("z was entered");
                        throw new InterruptedException("Command z interruption");
                    } else {
                        System.out.println("no such command");
                    }
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            } catch (InterruptedException ie) {
            }
            // Now notify ThreadC - it will wait() until this code is run
            synchronized(threadC) {
                threadC.notify();
            }
        }
    }
    
    public class ThreadC extends Thread {
    
        ThreadB threadB;
    
        public void setThreadB(ThreadB threadB) {
            this.threadB = threadB;
        }
    
        @Override
        public void run() {
                this.loopIt();
       }
    
        public void loopIt() {
            // Block until the lock can be obtained
            // We want thread B to run first, so the lock should be passed into Thread C constructor in an already locked state
            threadB.interrupt();
            synchronized(this) {
                try {
                    // Put this thread to sleep until threadB calls threadC.notify().
                    //
                    // Note: could replace this line with threadB.join() - and remove  
                    // from threadB the call to threadC.notify()
                    this.wait();
                } catch (InterruptedException ie) {
                }
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                String command = null;
                while (!"e".equals(command)) {
                    try {
                        command= reader.readLine();
                        if ("d".equals(command)) {   
                            System.out.println("d was entered");             
                        } else if ("e".equals(command)) {    
                            System.out.println("e was entered");            
                        } else if ("f".equals(command)) {
                            System.out.println("f was entered");
                        } else if ("z".equals("command")) {
                            System.out.println("z was entered");
                        } else { 
                            System.out.println("no such command");
                        };
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                }
            }        
        }
    }
    

    这篇关于扫描仪(System.in) - 如何取消/跳过输入等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆