如何暂停一个线程并在它停止的地方恢复它
how to pause a thread and resume it exactly where it was left off
我正在尝试为线程提供一个解决方案,以便在它停止的地方暂停和恢复。
下面是模拟我的问题的示例代码:后台有 2 个线程 运行:taskThread
和 busyThread
。当 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。
并发包中有两个非常有用的 类 - CountDownLatch
和 CyclicBarrier
。如果您只需要一次此行为,您可能需要第一个(因为它无法重置)。
线程 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);
}
}
}
我正在尝试为线程提供一个解决方案,以便在它停止的地方暂停和恢复。
下面是模拟我的问题的示例代码:后台有 2 个线程 运行:taskThread
和 busyThread
。当 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。
并发包中有两个非常有用的 类 - CountDownLatch
和 CyclicBarrier
。如果您只需要一次此行为,您可能需要第一个(因为它无法重置)。
线程 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);
}
}
}