Заставляем поток ждать от основного потока

Я прочитал много сообщений о том, как заставить потоки ждать, но я не могу заставить ничего работать. Я прочитал документ о ожидании, уведомлении, присоединении, блокировке ... но все еще не могу найти способ решить свою проблему.

У меня есть мой основной поток и еще один поток в фоновом режиме (пользователь не взаимодействует с ним, он просто делает свои собственные вещи). Тогда в основном потоке у пользователя будет возможность использовать некоторые функции, пока он не выйдет из программы. Я хочу, чтобы, когда пользователь решает использовать функцию, поток в фоновом режиме приостанавливается во время этой функции, а затем снова запускается после.

Я объясню это с помощью «псевдокода»:

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
        }
    }
}

Я не думаю, что мне следует использовать соединение, так как я хочу ждать не завершения другого потока, а завершения функции в другом потоке. Я думал, что блокировка была ответом, но я не мог заставить ее работать. Я пробовал это:

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
}

Но это не сработает.

Если вам нужно больше контекста: поток в фоновом режиме ожидает сообщения от сокета, и функции, которые может вызывать пользователь, также используют этот сокет. Итак, да, моей первой мыслью было поместить этот сокет как синхронизированный объект между двумя потоками, но мне тоже не удалось заставить его работать.

1
0
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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");

и так далее.

Повторите: просто создание объекта потока ничего не делает. Вы должны подумать о протокол, который можно использовать для достижения цели. Таким образом: сосредоточьтесь на аспектах дизайн здесь. Думайте о своей цепочке (ах) как о людях. А теперь спросите себя, что именно вам нужно указать этим людям для такого взаимодействия.

Ваша текущая реализация сводится к «разговору со случайным парнем на улице, чтобы затем уйти от него». Но как вы ожидаете, что случайный парень может отреагировать на вас после того, как вы уйдете? Вы не просили его номер телефона, так как же вы собираетесь отправлять ему сообщения?

да, вот почему я попробовал с замком; так как я сделал блокировку в main, а затем передал ее своему потоку, у меня есть что с этим справиться. Но это не сработало. Вот почему я попытался использовать синхронизированный объект, который используют как мой фоновый поток, так и мой основной поток. Тоже не сработало. Я также попытался сделать этот поток расширяемым потоком, а не реализуемым, поэтому я мог бы дать ему метод паузы, который я вызову в своем основном потоке. Типа, все, что я мог представить, для обработки этого потока в моем основном потоке. Я думал об очереди, но она довольно большая для единственного нужного мне варианта.

Ablia 10.08.2018 16:12

Проблема в том, что ваш код изначально не синхронизирует боковой и основной потоки! Вы предполагаете, что основной поток что-то делает первым, но это не будет работать все время. Вам абсолютно необходим барьер, который гарантирует, что оба потока достигнут барьера и находятся в заведомо исправном состоянии. Опять же: вам нужно сначала определить четкий протокол, который не оставляет места для двусмысленности.

GhostCat 10.08.2018 17:29
Ответ принят как подходящий

Вы можете использовать переменную 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 в основном потоке, изменения сразу же видны в фоновом потоке службы, потому что он непостоянен.

Другие вопросы по теме