使线程从主线程等待

时间:2018-08-10 13:50:48

标签: java multithreading locking wait

我读了很多有关使线程等待的信息,但是我什么都做不了。我已经阅读了有关等待,通知,加入,锁定...的文档,但是仍然找不到解决我的问题的方法。

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

我将在此处使用“伪”代码进行解释:

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
}

但是它不起作用。

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

2 个答案:

答案 0 :(得分:2)

在您的第一个示例中:

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
}

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

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

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

类似(此处为伪代码):

 Queue<String> commands = ...

 new EnhancedThread(commands).start();

以上内容将启动一个新线程,并且该线程可以在commands队列上“监听”命令。这样您的主线程便可以:

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

以此类推。

重复:仅创建线程对象不会执行任何操作。您必须考虑可以用于完成任务的 protocol 。因此:在这里着重于 design 方面。将您的线程视为人类。现在,问问自己,要让这些人进行这种互动,您到底需要指定什么?

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

答案 1 :(得分:1)

您可以使用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时,更改将立即在后台服务线程中可见,因为它是易变的。