如何暂停一个线程并将其恢复到它停止的位置

时间:2015-10-29 15:12:38

标签: java multithreading concurrency wait notify

我试图为一个线程提供一个解决方案来暂停和恢复其中断的位置。

所以这是一个模拟我的问题的示例代码:2个线程在后台运行:taskThread& busyThread。当busyThread位于系统繁忙区域时,taskThread必须立即进行alt /暂停,并从中断处继续。例如,如果在任务C(已完成)暂停taskThread,则应在D处继续。

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

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();
}
}

4 个答案:

答案 0 :(得分:1)

并发包中有两个非常有用的类 - 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();

修改

以下是我在修改代码时提出的问题,但我不清楚这是否是预期的行为。

请注意volatile上的CountDownLatch关键字 - 这里非常重要,否则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);
        }
    }

}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我建议您创建一个implements Runnable的课程,该课程只是跟踪您所在的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){

        }
    }

}

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

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:

  

应该来这里告诉taskThread暂停

taskThread.interupt();
  

应该发出什么来表示taskThread恢复

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

答案 3 :(得分:0)

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

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

和另一个帖子

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

你可以在多个等待线程中使用它,只需记住在通知all之后设置适当的条件为false。