Java线程休眠的四种方式:sleep()、wait()、await()、park()、join() 您所在的位置:网站首页 线程休眠会释放锁吗 Java线程休眠的四种方式:sleep()、wait()、await()、park()、join()

Java线程休眠的四种方式:sleep()、wait()、await()、park()、join()

2023-04-23 15:01| 来源: 网络整理| 查看: 265

Thrad.sleep() Thrad.sleep()并不会在休眠的时候释放锁 Thrad.sleep()有两个重载方法,分别为sleep(long millis)和sleep(long millis, int nanos) @Test public void test01() throws InterruptedException { Object lock = new Object(); Thread t1 = new Thread(() -> { try { synchronized (lock) { System.out.println(SDF.format(new Date()) + "子线程获取到锁并休眠10s"); Thread.sleep(10000); } System.out.println(SDF.format(new Date()) + "子线休眠完毕程释放锁"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); t1.start(); Thread.sleep(100); System.out.println(SDF.format(new Date()) + "主线程尝试获取锁"); synchronized (lock) { System.out.println(SDF.format(new Date()) + "主线程获取到锁"); } } 复制代码 运行结果 2023/04/10 22:23:37子线程获取到锁并休眠10s 2023/04/10 22:23:37主线程尝试获取锁 2023/04/10 22:23:47主线程获取到锁 2023/04/10 22:23:47子线休眠完毕程释放锁 复制代码

根据运行结果可以知道主线程一直在等待子线程休眠完成释放锁

给子线程设置中断状态可以释放锁并抛出interruptedException @Test public void test01() throws InterruptedException { Object lock = new Object(); Thread t1 = new Thread(() -> { try { synchronized (lock) { System.out.println(SDF.format(new Date()) + "子线程获取到锁并休眠10s"); Thread.sleep(10000); } System.out.println(SDF.format(new Date()) + "子线休眠完毕程释放锁"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); t1.start(); Thread.sleep(100); t1.interrupt(); // 给子线程设置中断状态 System.out.println(SDF.format(new Date()) + "主线程尝试获取锁"); synchronized (lock) { System.out.println(SDF.format(new Date()) + "主线程获取到锁"); } } 复制代码 运行结果 2023/04/10 22:25:41子线程获取到锁并休眠10s 2023/04/10 22:25:41主线程尝试获取锁 2023/04/10 22:25:41主线程获取到锁 Exception in thread "Thread-0" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted at ThreadTest.lambda$test01$0(ThreadTest.java:20) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at ThreadTest.lambda$test01$0(ThreadTest.java:16) ... 1 more 复制代码 Object.wait() 该方法属于Object定义的方法 Object.wait()休眠的时候会释放锁 Object.wait()有三个重载方法,分别为wait()、wait(long timeout)和wait(long timeout, int nanos) @Test public void test02() throws InterruptedException { Object lock = new Object(); Thread t1 = new Thread(() -> { try { synchronized (lock) { System.out.println(SDF.format(new Date()) + "子线程获取到锁并休眠10s"); lock.wait(5000); } System.out.println(SDF.format(new Date()) + "子线休眠完毕程释放锁"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); t1.start(); Thread.sleep(100); System.out.println(SDF.format(new Date()) + "主线程尝试获取锁"); synchronized (lock) { System.out.println(SDF.format(new Date()) + "主线程获取到锁"); Thread.sleep(6000); System.out.println(SDF.format(new Date()) + "主线程释放锁"); } Thread.sleep(5000); } 复制代码 运行结果 2023/04/11 20:41:52子线程获取到锁并休眠10s 2023/04/11 20:41:52主线程尝试获取锁 2023/04/11 20:41:52主线程获取到锁 2023/04/11 20:41:58主线程释放锁 2023/04/11 20:41:58子线休眠完毕程释放锁 复制代码

子线程lock.wait(5000)进行休眠后,主线程立即获取到锁,随即主线程进行Thread.sleep(6000)休眠但是不释放锁,子线程一直在等待主线程将锁释放。待主线程释放锁后,子线程拿到锁后执行完毕

同样给子线程设置中断状态可以释放锁并抛出interruptedException @Test public void test02() throws InterruptedException { Object lock = new Object(); Thread t1 = new Thread(() -> { try { synchronized (lock) { System.out.println(SDF.format(new Date()) + "子线程获取到锁并休眠10s"); lock.wait(); } System.out.println(SDF.format(new Date()) + "子线休眠完毕程释放锁"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); t1.start(); Thread.sleep(100); t1.interrupt(); // 给子线程设置中断状态 System.out.println(SDF.format(new Date()) + "主线程尝试获取锁"); synchronized (lock) { System.out.println(SDF.format(new Date()) + "主线程获取到锁"); } } 复制代码 运行结果 2023/04/11 20:51:07子线程获取到锁并休眠10s 2023/04/11 20:51:07主线程尝试获取锁 2023/04/11 20:51:07主线程获取到锁 Exception in thread "Thread-0" java.lang.RuntimeException: java.lang.InterruptedException at ThreadTest.lambda$test02$1(ThreadTest.java:43) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.InterruptedException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at ThreadTest.lambda$test02$1(ThreadTest.java:39) ... 1 more 复制代码

使用Object.wait()进行线程休眠时,可通过Object.notify()和Object.notifyAll()进行线程唤醒

notify()每次会唤醒第一个线程,接下来计算唤醒次数,唤醒接下来的n个等待线程,并倒序执行。例如10个线程正在休眠,notify()for循环执行三次,则唤醒的三个线程分别是Thread0、Thread2、Thread1

notifyAll()则会倒序唤醒每个线程

condition.await() 与Object.wait类似 对应Object.wait()方法: await()、awaitNanos(long nanosTimeout)、await(long time, TimeUnit unit) 对应Object.notify()、notifyAll()方法:signal()、signalAll() 同时await休眠时会释放锁 使用condition.awaitUninterruptibly()休眠时,可以忽略中断报错 @Test public void test03() throws InterruptedException { ReentrantLock lock = new ReentrantLock(); int queueMaxSize = 10; LinkedList queue = new LinkedList(); Condition consumerCondition = lock.newCondition(); Condition producerCondition = lock.newCondition(); // 生产者 Thread producer = new Thread(() -> { try { boolean flag = Boolean.TRUE; lock.lock(); while (flag) { while (queue.size() == queueMaxSize) { System.out.println("队列已满,暂停生产"); producerCondition.await(); // 调用condition的await()和signal()方法,都必须在lock保护之内 } queue.offer(1); consumerCondition.signal(); System.out.println("生产者生产一个元素,当前队列size=" + queue.size()); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } }); // 消费者 Thread consumer = new Thread(() -> { try { boolean flag = Boolean.TRUE; lock.lock(); while (flag) { while (queue.size() == 0) { System.out.println("队列已空,暂停消费"); consumerCondition.await(); // 调用condition的await()和signal()方法,都必须在lock保护之内 } queue.poll(); producerCondition.signal(); System.out.println("消费者消费一个元素,当前队列size=" + queue.size()); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } }); producer.start(); consumer.start(); Thread.sleep(10000); } 复制代码 运行结果 队列已空,暂停消费 生产者生产一个元素,当前队列size=1 生产者生产一个元素,当前队列size=2 生产者生产一个元素,当前队列size=3 生产者生产一个元素,当前队列size=4 生产者生产一个元素,当前队列size=5 生产者生产一个元素,当前队列size=6 生产者生产一个元素,当前队列size=7 生产者生产一个元素,当前队列size=8 生产者生产一个元素,当前队列size=9 生产者生产一个元素,当前队列size=10 队列已满,暂停生产 消费者消费一个元素,当前队列size=9 消费者消费一个元素,当前队列size=8 消费者消费一个元素,当前队列size=7 消费者消费一个元素,当前队列size=6 消费者消费一个元素,当前队列size=5 消费者消费一个元素,当前队列size=4 消费者消费一个元素,当前队列size=3 消费者消费一个元素,当前队列size=2 消费者消费一个元素,当前队列size=1 消费者消费一个元素,当前队列size=0 复制代码

使用condition.await()配合condition.signal()可以很容易实现一个生产者、消费者模式

LockSupport.park() LockSupport.park() 的实现原理是通过二元信号量做的阻塞。0 是阻塞,1是通行。unpark()方法会将信号量变为 1,不论执行多少次unpark(这里指凭证没有被消费),也只能变成1。 t1线程没有启动时,其他线程的unpark(),t1 接收不到 @Test public void test05() throws InterruptedException { Thread t1 = new Thread(() -> { System.out.println("子线程开始休眠,等待被唤醒"); LockSupport.park(); System.out.println("子线程被唤醒,继续休眠"); LockSupport.park(); System.out.println("子线程响应中断,但是没有异常,执行完毕"); }); LockSupport.unpark(t1); System.out.println("主线程唤醒子线程1"); Thread.sleep(100); t1.start(); Thread.sleep(100); System.out.println("主线程唤醒子线程2"); LockSupport.unpark(t1); Thread.sleep(1000); System.out.println("主线程对子线程进行中断处理"); t1.interrupt(); Thread.sleep(10000); // 确保子线程执行完毕 } 复制代码 运行结果 主线程唤醒子线程1 子线程开始休眠,等待被唤醒 主线程唤醒子线程2 子线程被唤醒,继续休眠 主线程对子线程进行中断处理 子线程响应中断,但是没有异常,执行完毕 复制代码

子线程在启动之前执行unpark(t1)是不起效果的

LockSupport.park()后有对应的LockSupport.unpark(t1)即可被唤醒

LockSupport.park()可以响应中断被唤醒,但是不会报异常错误

Thread.join() Thread.join()有三个重载方法,分别为join()、join(long timeout)和join(long millis, int nanos) 我们经常会碰到主线程中起了一个子线程,但子线程还未执行完毕主线程就已经结束了。此时需要让线程按照自己指定的顺序执行的时候,就可以利用这个方法 Thread.join()方法表示调用此方法的线程被阻塞,仅当该方法完成以后,才能继续运行 @Test public void test06() throws InterruptedException { Thread t1 = new Thread(() -> { try { System.out.println("t1线程开始休眠5s"); Thread.sleep(5000); System.out.println("t1线程休眠结束"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); Thread t2 = new Thread(() -> { try { System.out.println("t2线程等待t1线程"); t1.join(); System.out.println("t2线程开始休眠5s"); Thread.sleep(5000); System.out.println("t2线程休眠结束"); } catch (InterruptedException e) { throw new RuntimeException(e); } }); t1.start(); Thread.sleep(200); t2.start(); Thread.sleep(200); System.out.println("主线程等待t2线程"); t2.join(); System.out.println("主线程执行完毕"); } 复制代码 运行结果 t1线程开始休眠5s t2线程等待t1线程 主线程等待t2线程 t1线程休眠结束 t2线程开始休眠5s t2线程休眠结束 主线程执行完毕 复制代码

主线程一直在等待t2线程执行完毕,而t2线程又在等待t1线程,因此可以看到线程按照预想的顺序进行执行



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有