【问题标题】:Making a thread wait from main thread使线程从主线程等待
【发布时间】:2018-08-10 13:50:48
【问题描述】:

我已经阅读了很多关于让线程等待的消息,但我无法让任何东西起作用。我已经阅读了有关等待、通知、加入、锁定的文档……但仍然找不到解决我的问题的方法。

我在后台有我的主流和另一个流(用户不与之交互,它只是做他自己的事情)。然后在主流中,用户将有可能使用某些功能,直到他退出程序。我想要的是,当用户选择使用某个功能时,后台的流在此功能期间暂停,然后重新开始。

我将在这里用“伪”代码解释它:

main(args[]){
    new Thread(new Background(), "Background").start();
    while (user don't quit){
        //user choose a function
        -> find a way to pause Background thread
        chosenFunction();
        -> find a way to unpause the Background thread
    }
}

public class Background implements Runnable{
    public Background(){}
    public void run(){
        while (thread is not paused){
            //do some stuff
        }
    }
}

我认为我不应该使用join,因为我不想等待另一个线程的完成,而是等待另一个线程中的函数完成。我认为锁是答案,但我无法让它工作。我试过了:

main(args[]){
    ReentrantLock lock = new ReentrantLock();
    new Thread(new Background(lock), "Background").start();
    while (user don't quit){
        //user choose a function
        lock.lock();
        chosenFunction();
        lock.unlock();
    }
}

public class Background implements Runnable{
    private final ReentrantLock lock;
    public Background(ReentrantLock lock){
        this.lock = lock;
    }
    public void run(){
        while (!lock.islocked()){
            //do some stuff
        }
    }
}

或与:

public void run(){
    while(lock.isLocked){
        sychronized(this){
            wait();
        }
    }
//do some stuff
}

但它不会起作用。

如果您需要更多上下文:后台线程正在等待来自套接字的消息,并且用户可以调用的函数也在使用此套接字。所以是的,我的第一个想法是把这个套接字作为两个流之间的同步对象,但我也没有设法让它工作。

【问题讨论】:

    标签: java multithreading locking wait


    【解决方案1】:

    在你的第一个例子中:

    new Thread(new Background(), "Background").start();
    while (user don't quit){
        //user choose a function
        -> find a way to pause Background thread
        chosenFunction();
        -> find a way to unpause the Background thread
    }
    

    第一个问题是:为了了解其他对象,您需要某种句柄。你这里没有。

    含义:您的代码创建一个新线程并启动它。但是该线程的 reference 被丢弃。除非您保留对它们的引用,否则您无法识别对象。 Background 对象也是如此。

    换句话说:当您希望多个线程相互通信时,您需要在双方之间建立一个通信通道。例如:两个线程实现都可以访问的对象。

    点赞(这里是伪代码):

     Queue<String> commands = ...
    
     new EnhancedThread(commands).start();
    

    上面将启动一个新线程,并且该线程可以“侦听”commands 队列中的命令。所以你的主线程可以这样做:

     commands.add("COMMAND1");
     commands.add("SUSPEND");
    

    等等。

    重复:仅仅创建一个线程对象什么都不做。你必须想出一个可以用来完成事情的协议。因此:在这里关注设计方面。将您的线程视为人类。现在问问自己,要让这些人进行这种互动,你需要具体说明什么。

    您当前的实现归结为“与街上的一个随机人交谈,然后离开他。”但是,在您离开后,您如何期望随机的人会对您做出反应?你没有问他的电话号码,那你打算怎么给他发消息?

    【讨论】:

    • 是的,这就是我尝试使用 lock 的原因;因为我在 main 中做了锁定,然后将其提供给我的流,所以我有一些东西可以处理它。但它没有奏效。这也是我尝试使用同步对象的原因,我的后台线程和主线程都使用它。也没有用。我还尝试将此线程作为扩展线程而不是实现可运行的线程,因此我可以给它一个暂停方法,我将在我的主线程中调用它。就像,我能想象到在我的主流中处理这个线程的一切。我考虑过 Queue,但它对于我需要的唯一选项来说相当大。
    • 问题是你的代码最初没有同步侧线程和主线程!您假设主线程首先执行某些操作,但这不会一直有效。您绝对需要一个屏障来确保两个线程都到达屏障并处于已知的良好状态。再次重申:您需要首先定义一个明确的协议,不会给歧义留下空间。
    【解决方案2】:

    您可以使用volatile 变量。这是volatile变量的一个非常典型的用例。

    public void main() {
    
        BackgroundServiceThread bst = new BackgroundServiceThread();
        bst.start();
    
        while (true) {
            //user choose a function
            bst.isPaused = true;
            chosenFunction();
            bst.isPaused = false;
        }
    }
    
    private static class BackgroundServiceThread extends Thread {
    
        volatile boolean isPaused = false;
    
        @Override
        public void run() {
            while (true) {
                if (!isPaused) {
                    //do stuffs;
                }
            }
        }
    }
    
    private void chosenFunction() {
        //user choose function
    }
    

    当您在主线程中更新 isPaused 时,更改会立即在您的后台服务线程中可见,因为它是易变的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 2023-03-11
      • 1970-01-01
      • 2020-10-30
      • 1970-01-01
      • 2020-02-26
      • 1970-01-01
      相关资源
      最近更新 更多