十分钟搞定Java多线程-如何使用sleep()方法和TimeUnit暂停线程

  • Post author:
  • Post category:java


为什么要使用sleep暂停线程

有多种方法可以暂停或停止当前正在运行的线程,但是使用Thread.sleep()方法将线程置于睡眠状态才是暂停线程的正确方法。有些人会说,为什么不用wait和notify呢?仅仅为了暂停线程而使用这些方法并不是好方案,这些是有条件等待的方法,它们不依赖于时间。如果使用wait()阻塞的线程将一直等待,直到它所等待的条件发生改变。当然,你可以将timeout放在那里,但是毕竟wait()方法的用途是有所不同的,它们是为Java中的线程间通信而设计的。通过使用sleep()方法,可以将当前值暂停一段时间。因此你不应该使用sleep()来代替wait()和notify(),反之亦然。等待和通知不应该用来暂停线程的另一个原因是,它们需要锁。你只能从同步方法或块中调用它们,并获取和释放锁,这是比较昂贵的。

更重要的是,为什么仅仅为了暂停线程而引入锁呢?wait()和sleep()方法之间的关键区别之一是,

Thread.sleep()

将当前线程置于wait状态,但不会释放它持有的任何锁,但wait会在进入阻塞状态之前释放它持有的锁。

简而言之,多线程并不容易,即使是创建线程、停止线程或暂停线程这样的简单任务也需要对Java API有很好的了解。你需要在正确的地方使用正确的方法。如果你真的想要掌握多线程和并发性,我建议你在实践中阅读两次Java并发实践,并完成书中给出的每个示例。那本书将会改变你对多线程的认识,以及思考相关问题的思路。

如何使用sleep暂停线程

下面是相关的代码示例,使用Java中的Thread .sleep()和TimeUnit.sleep()方法来暂停正在运行的线程。在这个简单的程序中,我们有两个线程,主线程由JVM启动,通过调用公共静态void main(String args[])方法来执行Java程序。第二个线程是“T1”,是我们创建用来运行一个循环业务的。我们传递给这个线程的Runnable任务有一个无限的while循环,该循环一直运行到满足条件停止。仔细观察,就会发现我们使用了一个volatile修饰符来停止Java中的一个线程。

主线程首先启动子线程,然后在继承Runnable的Game类中使用stop()方法来停止线程。当T1线程启动时,进入一个循环里,然后暂停200毫秒。在这两者之间,我们还使用TimeUnit.sleep()方法使主线程进入睡眠状态,所以主线程将等待一段时间,直到T1线程执行任务结束。

在示例中,我们了解到在Java中暂停线程的两种方法,即使用Thread.sleep()方法和TimeUnit.sleep()方法。传递给Thread.sleep()的参数是毫秒单位的睡眠时间,但这在代码中并没有清晰体现,这就是TimeUnit类的作用所在。

你可以引用特定时间单元的TimeUnit实例,例如在调用sleep之前,先使用TimeUnit.SECONDS或TimeUnit.MICROSECOND。这样你就可以更清楚地看到一个线程将等待多长时间。简而言之,建议使用TimeUnit类的sleep()方法来暂停一个线程,因为它更具可读性。

import java.util.concurrent.TimeUnit;

import static java.lang.Thread.currentThread;

public class Thread6 {

    public static void main(String args[]) throws InterruptedException {
        Game game = new Game();

        Thread t1 = new Thread(game, "T1");
        //启动子线程
        t1.start();

        //停止子线程
        System.out.println(currentThread().getName() + " is stopping game thread");
        game.stop();

        //等待,确认子线程已经停止
        TimeUnit.MILLISECONDS.sleep(200);

        System.out.println(currentThread().getName() + " is finished now");
    }

}

class Game implements Runnable{
    private volatile boolean isStopped = false;

    public void run() {

        while(!isStopped){
            System.out.println("Game thread is running.....");
            System.out.println("Game thread is now going to pause");

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("Game thread is now resumed ..");
        }

        System.out.println("Game thread is stopped....");
    }

    public void stop(){
        isStopped = true;
    }
}

输出结果:

Game thread is running…..

Game thread is now going to pause

main is stopping game thread

Game thread is now resumed ..

Game thread is stopped….

main is finished now

关于sleep()方法的要点

现在已经知道了如何让线程处于睡眠状态或暂停状态,接下来看看Thread.sleep()方法的一些技术细节。

1) sleep()是一个静态方法,它总是将当前线程置为睡眠状态。

2) 你可以调用正在休眠的线程的interrupt()方法,来唤醒正在休眠的线程。

3) sleep方法并不能保证线程会精确地休眠到你指定的时间点,它的准确性取决于系统计时器,并且线程可能在此之前被唤醒。

4)它不会释放它所获得的锁。

总结

以上就是如何使用Thread.sleep()方法和TimeUnit的sleep()方法使线程暂停的内容,建议使用TimeUnit类,因为它提高了代码的可读性,虽然其实也不难记住传递给sleep()方法的参数是以毫秒为单位的。需要记住的两个关键要点,Thread.sleep()是一个静态方法,它总是将当前线程置为休眠状态,并且不会释放休眠线程持有的任何锁。



版权声明:本文为mcmoo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。