如何暂停一个线程并在它停止的地方恢复它

how to pause a thread and resume it exactly where it was left off

我正在尝试为线程提供一个解决方案,以便在它停止的地方暂停和恢复。

下面是模拟我的问题的示例代码:后台有 2 个线程 运行:taskThreadbusyThread。当 busyThread 系统繁忙区域 时,taskThread 必须立即 alt/pause 并从它停止的地方恢复。例如,如果 taskThread 在任务 C 处暂停(完成),它应该在 D 处恢复。

我尝试使用 wait, notify on taskThread 但没有成功。

public class Test
{ 
   private Thread taskThread;
   private Thread busyThread;

public static void main(String args[]) throws Exception
{ 
    Test t = new Test();
    t.runTaskThread();
    t.runBusyThread(); 
} 


public void runTaskThread()
{
    taskThread = new Thread(new Runnable(){

        @Override
        public void run()
        {
            for (int x=0; x<100; x++)
            {
                try
                {                       
                    System.out.println("I'm doing task A for process #"+x);
                    Thread.sleep(1000);

                    System.out.println("I'm doing task B for process #"+x);
                    Thread.sleep(200);

                    System.out.println("I'm doing task C for process #"+x);
                    Thread.sleep(300);

                    System.out.println("I'm doing task D for process #"+x);
                    Thread.sleep(800);

                    System.out.println("\n\n");

                } catch (InterruptedException e)
                {                       
                    e.printStackTrace();
                }                                       
            }

        }});

    taskThread.start();
}

public void runBusyThread()
{
    busyThread = new Thread(new Runnable(){

        @Override
        public void run()
        {
            while (true)
            {
                Random rand = new Random();
                int randomNum = rand.nextInt(1000);
                if (randomNum<400)
                {
                    System.out.println("Wait...system is busy!!!");                     
                    try
                    {       //what should come here to to signal taskThread to paused
                            Thread.sleep(3000);

                             //what should come here to to signal taskThread to resume

                    } catch (InterruptedException e)
                    { 
                    }
                } else
                {
                    try
                    {
                        Thread.sleep(300);
                    } catch (InterruptedException e)
                    {
                    }   
                }                       
            }               
        }});    

    busyThread.start();
}
}

它将使用已弃用的方法完成 Thread.suspend/resume。 它们已被弃用,因为它们容易死锁,而像锁这样的并发机制以设计明确的方式运行(但仍然容易死锁)。

我建议创建一个 implements Runnable 的 class,它只是跟踪您所在的 stages

仅作为示例(请相应更改)

class MyRunnable implements Runnable {
    private int stage = 0; // if you want it gloabally, then use static
    @Override
    public void run() {
        try{
            switch(stage){
                case 1:
                    System.out.println("1");
                    stage++;

                case 2:
                    System.out.println("2");
                    Thread.sleep(2000);
                    stage++;
                default:
                    stage = 0;

            }
        }catch (Exception e){

        }
    }

}

现在要使用这样的 class 你只需要创建一个新线程 例如:

public static void main(String[] args) throws Exception{

  MyRunnable myRunnable=new MyRunnable();
  new Thread(myRunnable).start(); //it prints 1

  Thread.sleep(1000);

  new Thread(myRunnable).start(); //prints 2 follow by 2 sec sleep

}

注意:

这个例子并不是为了准确地回答问题,而是展示了如何做到这一点的逻辑。

编辑 1:

what should come here to to signal taskThread to paused

taskThread.interupt();

what should come here to to signal taskThread to resume

taskThread=new Thread(myRunnable);
taskThread.start();

我更喜欢 wait() 和 notifyAll() 而不是 sleep()。 有一个布尔 systemBusy,实现 get 和 set 方法; 现在在 thread1

    run(){
       synchronize(something){
          while(isSystemBusy()){
             try{
                wait();}
             catch{}
          }
       }
    }

在另一个线程上

        run(){
           setSystemBusy(true);
           //piece of code
           //task finished
           notifyAll();
           setSystemBusy(false);
        }

您可以在多个等待线程中使用它,只需记住在通知所有线程后设置适当的 while 条件 false。

并发包中有两个非常有用的 类 - CountDownLatchCyclicBarrier。如果您只需要一次此行为,您可能需要第一个(因为它无法重置)。

线程 1 会等待直到线程 2 通知。一旦倒数到 0,线程 1 将永远不会在 await():

处再次阻塞
CountDownLatch cdl = new CountDownLatch(1);

// thread 1:
cdl.await();

// thread 2:
cdl.countDown();

线程将在 await() 处阻塞,直到正好有两个线程在等待:

CyclicBarrier barrier = new CyclicBarrier(2);

// both threads:
barrier.await();

编辑:

这是我在修改您的代码时想到的,但是我不清楚这是否是预期的行为。

注意 CountDownLatch 上的 volatile 关键字 - 它在这里非常重要,否则 taskThread 可能会缓存初始对象 (new CountDownLatch(0)),因此永远不会阻塞。

public class Test {

    private Thread taskThread;
    private Thread busyThread;

    private volatile CountDownLatch cdl = new CountDownLatch(0);

    public static void main(String args[]) throws Exception {
        Test t = new Test();
        t.runTaskThread();
        t.runBusyThread();
    }

    public void runTaskThread() {
        taskThread = new Thread(() -> {
            for (int x = 0; x < 100; x++) {
                waitIfSystemBusy();
                System.out.println("I'm doing task A for process #" + x);
                sleep(1000);

                waitIfSystemBusy();
                System.out.println("I'm doing task B for process #" + x);
                sleep(200);

                waitIfSystemBusy();
                System.out.println("I'm doing task C for process #" + x);
                sleep(300);

                waitIfSystemBusy();
                System.out.println("I'm doing task D for process #" + x);
                sleep(800);

                System.out.println("\n\n");
            }
        });

        taskThread.start();
    }

    public void runBusyThread() {
        busyThread = new Thread(() -> {
            while (true) {
                Random rand = new Random();
                int randomNum = rand.nextInt(1000);
                if (randomNum < 400) {
                    System.out.println("Wait...system is busy!!!");
                    cdl = new CountDownLatch(1); // signal taskThread to pause
                    sleep(3000);
                    cdl.countDown(); // signal taskThread to resume
                } else {
                    sleep(300);
                }
            }
        });

        busyThread.start();
    }

    private void waitIfSystemBusy() {
        try {
            cdl.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}