如何按顺序优雅地停止java线程?

时间:2013-06-04 15:06:34

标签: java multithreading

我已按顺序启动线程,但我不知道如何以相反的顺序停止它们。 例如: 它们是这样开始的:A-> B-> C-> D 并且我希望它们停止:D-> C-> B-> A 我根本不知道如何停止线程,甚至不按此顺序停止线程。 我感谢任何帮助或建议。

import java.util.*;

class Service extends Thread
{
  private RobotController controller;
  private String robotID;
  private byte[] lock;                                          

  public Service(RobotController cntrl, String id)
  {
    controller = cntrl;
    robotID = id;
  }

  public byte[] getLock() { return lock;}                                                              
  public void run()
  {
    lock = new byte[0]; 
    synchronized(lock)                                          
    {

      byte[] data;
      while ((data = controller.getData()) == null)
      {
        try {
          lock.wait();  
        } catch (InterruptedException ie) {}
      }
      System.out.println("Robot " + robotID + " Working");
    }
  }
}

class RobotController
{
  private byte[] robotData;
  private Vector threadList = new Vector();                      
  private Service thread_A;
  private Service thread_B;
  private Service thread_C;
  private Service thread_D;
  private volatile boolean done;

  public void setup(){
    thread_A = new Service(this, "A");
    thread_B = new Service(this, "B");
    thread_C = new Service(this, "C");
    thread_D = new Service(this, "D");
    threadList.addElement(thread_A);                               
    threadList.addElement(thread_B);                                
    threadList.addElement(thread_C);                                
    threadList.addElement(thread_D);                                
    thread_A.start();
    thread_B.start();
    thread_C.start();
    thread_D.start();
    start();
    stop();

  }

  public void start()
  { 
      System.out.println("Thread starts");
      {
            for (int i=0; i <= 3; i++)                                    
            {
              try {
                Thread.sleep(500);
              }catch (InterruptedException ie){}
              putData(new byte[10]);
              Service rbot = (Service)threadList.elementAt(i);               
              byte[] robotLock = rbot.getLock();                        
              synchronized(robotLock) {                                     
                robotLock.notify();                                      
              }
            }
      }
  }

  public void stop()
  {
      {

      }
  }

  public synchronized byte[] getData()                          
  {
    if (robotData != null)
    {
      byte[] d = new byte[robotData.length];
      System.arraycopy(robotData, 0, d, 0, robotData.length);
      robotData = null;
      return d;
    }
    return null;
  }

  public void putData(byte[] d) { robotData = d;}

  public static void main(String args[])
  {
    RobotController controller = new RobotController();
    controller.setup();
  }
}

4 个答案:

答案 0 :(得分:2)

如果我想明确地终止它们,我通常会在我的线程中包含类似cancel()方法的内容。

class Service extends Thread {
    private volatile boolean cancel = false;

    public void cancel() {
        cancel = true;
    }

    public void run() {
        ...
        while (!cancel && (data = controller.getData()) == null) {
        ...
        }
    }
}

按照mre的建议将线程保持在堆栈中,然后弹出堆栈并在每个线程上调用cancel然后interrupt

答案 1 :(得分:2)

  

我按顺序启动了线程,但我不知道如何以相反的顺序停止它们。

这很难做到。有一些方法可以通过设置volatile关闭布尔值或中断它们来停止线程,但是这些机制都不能保证立即停止线程。

您构建它们时当然可以保留List<Thread>,然后拨打Collections.reverse(threadList),然后依次致电thread.interrupt()。如果必须按顺序完成它们,那么你应该打断它们,然后加入它们。类似的东西:

 Collections.reverse(threadList);
 for (Thread thread : threadList) {
      thread.interrupt();
      thread.join();
 }

然后每个线程应该做类似的事情:

 while (!Thread.currentThread().isInterrupted()) {
     ...
 }

请注意,如果您正在运行Thread.sleep(...)或其他抛出InterruptedException的方法,则需要重新启用中断标志:

  try {
      Thread.sleep(...);
  } catch (InterruptedException e) {
      // by convention if InterruptedException thrown, interrupt flag is cleared
      Thread.currentThread().interrupt();
      ...
  }

答案 2 :(得分:1)

让每个线程保持对下一个要启动的线程的引用。然后每个线程可以定期检查线程是否仍然存活。如果不是,那个线程应该终止。当它发生时,前一个线程会注意到并终止,依此类推。

abstract class ChainThread extends Thread {

  private final Thread next;

  ChainThread(Thread next) { this.next = next; }

  @Override
  public final void run() {
    next.start();
    while (!Thread.currentThread().isInterrupted() && next.isAlive()) {
      do();
    }
  }

  abstract void do();

}

答案 3 :(得分:0)

如果我正确读取Service代码,它会一直等到有数据要执行,然后结束。因此,您实际上不需要明确的stopcancel类型信号,线程将在它们工作后自行终止。

要强制执行关机排序,您可以让每个Service知道之前的Service,然后拨打previousService.join()。假设没有抛出InterruptedExceptions,它们将在看到控制器有数据后按顺序关闭。

以这种方式创建服务:

    Service serviceA = new Service(controller, "A", null);
    Service serviceB = new Service(controller, "B", serviceA);
    Service serviceC = new Service(controller, "C", serviceB);
    Service serviceD = new Service(controller, "D", serviceC);

并且编辑实现以仅在依赖Services完成后才退出:

private final RobotController controller;
private final String robotID;
private byte[] lock;
private final Service dependentService;

public Service(RobotController cntrl, String id, Service dependentService) {
    controller = cntrl;
    robotID = id;
    this.dependentService = dependentService;
}

public byte[] getLock() {
    return lock;
}

@Override
public void run() {
    lock = new byte[0];
    synchronized (lock) {

        byte[] data;
        while ((data = controller.getData()) == null) {
            try {
                lock.wait();
            }
            catch (InterruptedException ie) {
            }
        }
        System.out.println("Robot " + robotID + " Working");
    }

    if (dependentService != null) {
        try {
            dependentService.join();
        }
        catch (InterruptedException e) {
            this.interrupt();
        }
    }
}