2016-02-23 5 views
2

Это пример кода с использованием java-потока. Проблема в том, что я не могу приостановить поток.Java Thread suspend не работает

public class RunnableDemo implements Runnable { 
    public Thread t; 
    private String threadName; 
    boolean suspended = false; 
    RunnableDemo(String name){ 
     threadName = name; 
     System.out.println("Creating " + threadName); 
    } 
    public void run() { 
     System.out.println("Running " + threadName); 
     try { 
     while (true) { 
      System.out.println("Thread: " + threadName + ", " + i); 
      // Let the thread sleep for a while. 
      Thread.sleep(300); 
      synchronized(this) { 
       while(suspended) { 
        wait(); 
       } 
      } 
     } 
    } catch (InterruptedException e) { 
     System.out.println("Thread " + threadName + " interrupted."); 
    } 
    System.out.println("Thread " + threadName + " exiting."); 
    } 
    public void start() 
    { 
     System.out.println("Starting " + threadName); 
     if (t == null) 
     { 
     t = new Thread (this, threadName); 
     t.start(); 
     } 
    } 
    public void suspend() { 
     suspended = true; 
    } 

Функция приостановки ниже не работает:

RunnableDemo R1 = new RunnableDemo("Thread-1"); 
R1.start(); 
R1.suspend(); // This line does not work and thread continues ... 

На самом деле нить не видит новое значение для suspended, когда я звоню suspend(). Есть идеи ?

+2

Функция 'suspend' не синхронизирована. Таким образом, ваш 'synchronized (this)' блок на самом деле ничего не делает. Только один поток вызывает 'run' в любом случае, поэтому вы не синхронизируете его ни с чем другим. Вам также нужно вызвать 'notify' в' suspend', иначе поток не проснется. –

ответ

1

Использование wait() может не работать так, как вы ожидаете. Ожидание/уведомление построено как простая реализация контекста параллельного программирования sempaphore (как объекта с широким экраном экземпляра). Вызов уведомления() из любой другой нити, не блокирующей монитор экземпляра объекта нити, не будет работать, см. Java Wait and Notify: IllegalMonitorStateException

Вы можете легко достичь своей цели, регулярно проверяя флаг подвески и просто подождите немного, если ваша нить ничего не должен делать:

public class SuspendDemo implements Runnable { 
    public Thread t; 
    private final String threadName; 
    boolean suspended = false; 
    SuspendDemo(final String name){ 
     threadName = name; 
     System.out.println("Creating " + threadName); 
    } 

    @Override 
    public void run() { 
     System.out.println("Running " + threadName); 
     try { 
      while (true) { 
       System.out.println("Thread: " + threadName); 
       // Let the thread sleep for a while. 
       Thread.sleep(300); 
       while(suspended) { 
        System.out.println("suspended"); 
        Thread.sleep(50); 
       } 
      } 
     } catch (final InterruptedException e) { 
      System.out.println("Thread " + threadName + " interrupted."); 
     } 
     System.out.println("Thread " + threadName + " exiting."); 
    } 

    public void start() { 
     System.out.println("Starting " + threadName); 
     if (t == null) { 
      t = new Thread (this, threadName); 
      t.start(); 
     } 
    } 

    void suspend() { 
     suspended = true; 
    } 

    void resume() { 
     suspended = false; 
     notify(); 
    } 

    public static void main(final String[] args) throws InterruptedException { 
     final SuspendDemo R1 = new SuspendDemo("Thread-1"); 
     R1.start(); 
     R1.suspend(); 
     Thread.sleep(500); 
     R1.resume(); 
    } 
} 

Результирующая:

> Creating Thread-1 
> Starting Thread-1 
> Running Thread-1 
> Thread: Thread-1 
> suspended 
> suspended 
> suspended 
> suspended 
> Thread: Thread-1 
> Thread: Thread-1 
> Thread: Thread-1 

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

Следующий пример решает проблему с ожидания() и notifyAll(). Обратите внимание на использование синхронизированных методов для блокировки монитора объекта потока вместо блоков synchronize (this).

public class SuspendDemo implements Runnable { 
    public Thread t; 
    private final String threadName; 
    boolean suspended = false; 
    SuspendDemo(final String name){ 
     threadName = name; 
     System.out.println("Creating " + threadName); 
    } 

    @Override 
    public void run() { 
     System.out.println("Running " + threadName); 
     try { 
      while (true) { 
       System.out.println("Thread: " + threadName); 
       // Let the thread sleep for a while. 
       Thread.sleep(300); 
       work(); 
      } 
     } catch (final InterruptedException e) { 
      System.out.println("Thread " + threadName + " interrupted."); 
     } 
     System.out.println("Thread " + threadName + " exiting."); 
    } 

    synchronized protected void work() throws InterruptedException { 
     while(suspended) { 
      System.out.println("suspended"); 
      wait(); 
      System.out.println("resumed"); 
     } 
    } 

    public void start() { 
     System.out.println("Starting " + threadName); 
     if (t == null) { 
      t = new Thread (this, threadName); 
      t.start(); 
     } 
    } 

    synchronized void suspend() { 
     suspended = true; 
     notifyAll(); 
    } 

    synchronized void resume() { 
     suspended = false; 
     notifyAll(); 
    } 

    public static void main(final String[] args) throws InterruptedException { 
     final SuspendDemo R1 = new SuspendDemo("Thread-1"); 
     R1.start(); 
     R1.suspend(); 
     Thread.sleep(500); 
     R1.resume(); 
    } 
} 
+0

Спасибо. Я получил java.lang.IllegalMonitorStateException, когда он достиг уведомления(). Более того, когда я делаю объект этого класса в другом классе, он не работает. –

+0

Проверьте код еще раз. Если вы опустите синхронизированное ключевое слово из suspend или resume, вы получите исключение IllegalMonitorStateException. Важно сначала получить блокировку на мониторе (синхронизация позаботится об этом). Можете ли вы уточнить, что вы подразумеваете под «объектом этого класса в другом классе» и что не работает? –

+0

Вы создаете R1 внутри одного и того же класса в основной функции. Я сказал, что когда вы создаете R1 в другом классе, тогда suspend() не работает. –

3

Declare suspended в volatile:

volatile boolean suspended = false; 
+0

Это не позволит возвратить вызов 'wait()'. – VGR

+0

Спасибо, но это не сработало для меня. Все еще в потоке «приостановлено» равно false –

1

Это не совсем ясно для меня, что вы пытаетесь достичь, но вот несколько замечаний и советов, которые могут помочь:

  • К время основной поток завершил метод suspend(), второй поток «Thread-1», вероятно, даже не вошел в цикл. Вы увидите это, если добавить дополнительный отладочный вывод в suspend() и до и после wait(). Противоположность также может быть правдой, и вы достигнете звонка до wait() до того, как будет установлено значение suspend. Затем, как только вызывается wait(), вы не увидите никаких обновлений в «Thread-1», так как он ждет.
  • Метод wait() никогда не вернется. Для этого синхронизируйтесь на том же объекте, который вы синхронизируете при вызове wait(), то есть R1 в основном методе, и звоните notifyAll() по этому объекту. Вы также можете сделать это в своем методе suspend().
  • Этот подход делает методы вроде Thread.sleep() практически ненужными. Вызов wait() не активен в ожидании и не будет потреблять значительные ресурсы.

Короче говоря, изменить Suspend-метод

void suspend() { 
    suspended = true; 
    synchronized (this) { 
     this.notifyAll(); 
    } 
} 

это изменится, как ваша программа ведет себя и сделать его более ясно, что происходит. Но в любом случае это не похоже на то, что «suspend» - хорошее имя для метода, до или после, но если вы экспериментируете с этим, вы можете лучше понять, как вы можете достичь того, чего вы хотите достичь.

+0

Проблема в том, что «приостановленное» значение в потоке всегда неверно, хотя suspend() превращает его в true. –

+0

Гарантия не предоставляется. Вы также можете достичь своего вызова, чтобы подождать(), прежде чем приостановить действие станет истинным. Затем вы ждете() и больше не увидите обновлений. Сделайте notifyAll(), и вы восстановите Thread-1 и увидите обновление. –

+0

Я уведомил All() в конце suspend(). Я получил исключение: java.lang.IllegalMonitorStateException –