如何让一个正在执行的线程暂停?

参考回答

在Java中,可以通过以下方法让一个正在执行的线程暂停:

  1. 使用Thread.sleep()
    • 暂停线程一段时间,但不释放锁。
    • 格式:Thread.sleep(milliseconds)
  2. 使用wait()notify()
    • 线程进入等待状态,必须与synchronized配合使用。
    • 线程暂停时会释放锁,其他线程可以进入临界区。
  3. 使用显式标志控制线程运行
    • 通过共享变量控制线程逻辑,暂停和恢复线程执行。
  4. 使用LockSupport.park()LockSupport.unpark()
    • 提供更灵活的线程挂起和恢复机制。

详细讲解与拓展

1. 使用Thread.sleep()

Thread.sleep()会让当前线程暂停指定的时间,然后自动恢复。

示例:暂停1秒

public class SleepExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("Thread running...");
            try {
                Thread.sleep(1000); // 暂停1秒
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted");
            }
            System.out.println("Thread resumed");
        });
        thread.start();
    }
}

关键点

  • Thread.sleep()是静态方法,只影响当前线程。
  • 会抛出InterruptedException,需要进行捕获处理。
  • 线程暂停期间不会释放锁。

2. 使用wait()notify()

wait()让线程进入等待状态,必须在synchronized块中调用。notify()用于唤醒一个等待的线程。

示例:通过wait()notify()暂停和恢复线程

public class WaitNotifyExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread waiting...");
                    lock.wait(); // 暂停线程
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread resumed");
            }
        });

        thread.start();

        try {
            Thread.sleep(1000); // 主线程暂停1秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (lock) {
            lock.notify(); // 恢复线程
            System.out.println("Thread notified");
        }
    }
}

关键点

  • wait()会释放锁,使其他线程可以获取锁。
  • notify()只能唤醒一个等待的线程;使用notifyAll()可以唤醒所有等待线程。
  • 必须在synchronized块中使用,否则会抛出IllegalMonitorStateException

3. 通过显式标志控制线程

通过共享变量可以控制线程的执行状态,适合实现更灵活的线程控制。

示例:暂停和恢复线程

public class FlagControlExample {
    private static volatile boolean paused = false;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                if (paused) {
                    System.out.println("Thread paused");
                    synchronized (FlagControlExample.class) {
                        try {
                            FlagControlExample.class.wait(); // 等待被唤醒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println("Thread running...");
                try {
                    Thread.sleep(500); // 模拟任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();

        try {
            Thread.sleep(1000); // 主线程暂停1秒
            paused = true; // 暂停线程
            Thread.sleep(2000);
            synchronized (FlagControlExample.class) {
                paused = false;
                FlagControlExample.class.notify(); // 恢复线程
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

关键点

  • 通过volatile变量确保线程之间的可见性。
  • 配合wait()notify()来暂停和恢复线程。

4. 使用LockSupport.park()LockSupport.unpark()

LockSupport提供更灵活的线程挂起和恢复机制,与wait()notify()不同,它不需要配合synchronized

示例:暂停和恢复线程

import java.util.concurrent.locks.LockSupport;

public class LockSupportExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("Thread running...");
            LockSupport.park(); // 暂停线程
            System.out.println("Thread resumed");
        });

        thread.start();

        try {
            Thread.sleep(1000); // 主线程暂停1秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        LockSupport.unpark(thread); // 恢复线程
        System.out.println("Thread unparked");
    }
}

关键点

  • park()暂停线程。
  • unpark(Thread thread)恢复指定线程。
  • 不需要锁,也不会抛出异常,适合更底层的线程控制。

扩展知识

线程暂停的注意事项

  1. Thread.suspend()Thread.resume()已被弃用
  • 这些方法容易导致线程死锁问题,因此不推荐使用。
  1. 避免使用忙等待
  • 例如,通过循环和检查标志来暂停线程会浪费CPU资源。
  • 应使用wait()LockSupport来更高效地暂停线程。
  1. 与中断配合使用
  • 如果线程可能在暂停期间被中断,需要正确处理InterruptedException

  • 示例:

    “`java
    if (Thread.currentThread().isInterrupted()) {
    System.out.println("Thread was interrupted");
    return;
    }
    “`

选择适合的暂停方式

  • 如果只需要短暂暂停,推荐使用Thread.sleep()
  • 如果需要线程协调,推荐使用wait()notify()或显式标志。
  • 如果需要更底层的控制,推荐使用LockSupport.park()

总结

线程的暂停和恢复可以通过Thread.sleep()wait()/notify()、共享变量、或LockSupport实现。选择合适的方式取决于具体的场景需求,避免使用废弃的API,并注意线程安全问题

发表评论

后才能评论