【JUC基础】09. LockSupport

这篇具有很好参考价值的文章主要介绍了【JUC基础】09. LockSupport。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、什么是LockSupport

 

LockSupport是一个线程阻塞工具,可以在线程任意位置让线程阻塞。线程操作阻塞的方式其实还有Thread.suspend()和Object.wait()。而LockSupport与suspend()相比,弥补了由于resume()方法而导致线程被挂起(类似死锁)的问题,也弥补了wait()需要先获得某个对象锁的问题,也不会抛出InterruptedException异常。

【JUC基础】09. LockSupport

相关API:

【JUC基础】09. LockSupport

2、suspend()和resume()

说到线程阻塞,除了Object.wait()和Object.notify()两种以外,还有Thread.suspend()和Thread.resume()。不过当前这两组API已被弃用,因为他们可能会导致死锁情况发生。

【JUC基础】09. LockSupport

【JUC基础】09. LockSupport

示例代码:

package locksupport;

import java.util.concurrent.TimeUnit;

/**
 * @author Shamee loop
 * @date 2023/5/19
 */
public class ThreadSuspendTest {

    static Object syncObject = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            synchronized (syncObject) {
                System.out.println(Thread.currentThread().getName() + "执行中,准备挂起");

                // 线程挂起
                Thread.currentThread().suspend();
            }
        }, "Thread-1");


        Thread thread2 = new Thread(() -> {
            synchronized (syncObject) {
                System.out.println(Thread.currentThread().getName() + "执行中,准备挂起");
                // 线程挂起
                Thread.currentThread().suspend();
            }
        }, "Thread-2");

        thread1.start();
        TimeUnit.SECONDS.sleep(1);
        thread2.start();
        // 继续执行
//        System.out.println("thread1线程准备执行了resume");
        thread1.resume();
//        System.out.println("thread1线程执行了resume");
        // 继续执行
//        System.out.println("thread2线程准备执行了resume");
        thread2.resume();
//        System.out.println("thread2线程执行了resume");
        thread1.join();
        thread2.join();
        System.out.println("程序运行结束");

    }
}

这里模拟了两个线程,运行过程中suspend()挂起,然后使用resume()让线程继续执行。

运行结果:

【JUC基础】09. LockSupport

可以看到程序无法退出,也无法打印“程序运行结束”日志。这就说明程序被永远挂起。原因是suspend()在导致线程暂停的同时,不会释放任何资源。此时其他线程想要访问被占用的锁时,都会导致阻塞。直到线程上进行了resume(),被挂起的线程才能继续。但是如果resume()方法操作以外的在suspend()之前进行了,那么被挂起的资源就尽可能永远被挂起而无法继续。

这里更加注意的时候,这时候被挂起的线程,状态还是Runnable,这些估计也是JDK不推荐的原因吧。

我们将上面几行注释的代码打开,在运行以下:

【JUC基础】09. LockSupport

我们发现thread2的resume()方法在suspend()之前就进行了。因此也解释了为什么thread2没有被继续执行的原因。

3、park()和unpark()

官方文档说了,LockSupport有两个重要的方法,park()和unpark()。而这两个方法很好的弥补了suspend()和resume()的不足。我们上述同等代码,用LockSupport来试下。

package locksupport;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @author Shamee loop
 * @date 2023/5/19
 */
public class LockSupportTest {

    static Object syncObject = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            synchronized (syncObject) {
                System.out.println(Thread.currentThread().getName() + "执行中,准备挂起");
                LockSupport.park();
            }
        }, "Thread-1");


        Thread thread2 = new Thread(() -> {
            synchronized (syncObject) {
                System.out.println(Thread.currentThread().getName() + "执行中,准备挂起");
                LockSupport.park();
            }
        }, "Thread-2");

        thread1.start();
        TimeUnit.SECONDS.sleep(1);
        thread2.start();

        // 继续执行
//        System.out.println("thread1线程准备执行了unpark");
        LockSupport.unpark(thread1);
//        System.out.println("thread1线程执行了unpark");
        // 继续执行
//        System.out.println("thread2线程准备执行了unpark");
        LockSupport.unpark(thread2);
//        System.out.println("thread2线程执行了unpark");

        thread1.join();
        thread2.join();
        System.out.println("程序运行结束");
    }
}

运行结果:

【JUC基础】09. LockSupport

可以看到程序正常退出,也打印出“程序运行结束”日志。而代码中只是将原本的suspend()方法替换成LockSupport.park(),将thread1.resume()替换成LockSupport.unpark(thread1)。

这是因为LockSupport使用的是类似信号量的机制。他为每个线程准备了一个许可,如果许可可用,那么park()方法会立刻返回,并且消费这个许可(也就是将许可变成不可用)。如果许可不可用,就会阻塞,而unpark()则是使得一个许可变成可用,但是和信号量不同的时,许可不能累加,不可能拥有超过一个许可。

所以这个特点就使得,即使unpark()方法执行发生在park()之前,他也可以是下一次的park()方法立即返回(因为当前的许可是可用的)。

不仅如此,通常使用park()挂起的状态,不会像suspend()还是Runnabele,他会直接给出waiting状态,同时堆栈也会体现由于park()方法引起,因此相比suspend()来说也更加友好。

我们将上述代码的注释打开,看下运行结果:

【JUC基础】09. LockSupport

可以看到,thread2的unpark()就算运行在了park()之前,程序依然正常运行结束。

4、中断影响

LockSupport方法还支持中断影响。但是他的中断并不是直接抛出InterruptedException,而是默默返回,我们可以从Thread.interrupted方法中获得中断标记。

如代码:

package locksupport;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @author Shamee loop
 * @date 2023/5/19
 */
public class LockSupportTest {

    static Object syncObject = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(LockSupportTest::doExecuteOn, "Thread-1");
        Thread thread2 = new Thread(LockSupportTest::doExecuteOn, "Thread-2");

        thread1.start();
        TimeUnit.SECONDS.sleep(1);
        thread2.start();

        thread1.interrupt();
        LockSupport.unpark(thread2);

    }

    private static void doExecuteOn(){
        synchronized (syncObject) {
            System.out.println(Thread.currentThread().getName() + "执行中,准备挂起");
            LockSupport.park();
            if(Thread.interrupted()){
                System.out.println(Thread.currentThread().getName() + "中断了");
            }
            System.out.println(Thread.currentThread().getName() + "执行结束");
        }
    }

}

执行结果:

【JUC基础】09. LockSupport

我们可以看到thread1可以立马响应中断,并且返回,甚至都不用unpark()。返回后,外面的thread2才能占用资源,并最终由unpark(thread2)操作,程序结束。

5、小结

前面在《【JUC基础】08. 三大工具类》中我们介绍了三大使用的线程辅助类,这里单独介绍线程阻塞控制类。因为我觉得这个工具类和前面的辅助类还是不太一样的。线程的阻塞,唤起是多线程开发中不可或缺的,因此单独拿出来讲。这里使用简单的代码程序说明,希望能有所收获。一天进步一点点~文章来源地址https://www.toymoban.com/news/detail-459694.html

到了这里,关于【JUC基础】09. LockSupport的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java基础-多线程&JUC-线程池和自定义线程池

    主要核心原理 不推荐Executors创建没有上线的线程池,建议使用自定义的线程池; Java工具类创建线程池; 当只有3个任务时,直接上处理机运行; 当有6个任务时,任务1-3上处理机运行,任务4-6进入阻塞队列等待; 当有9个任务时,任务1-3上处理机运行,任务4-6进入阻塞队列等

    2024年02月12日
    浏览(30)
  • 【从0开始编写webserver·基础篇#01】为什么需要线程池?写一个线程池吧

    参考: 1、游双Linux高性能服务器编程 2、TinyWebServer 注:虽然是\\\"从0开始\\\",但最好对(多)线程、线程同步等知识点有所了解再看,不然可能有些地方会理解不到位(但也有可能是我没说明到位,水平有限,见谅) Web服务器需要 同时处理多个客户端请求 ,并且每个请求可能

    2024年02月04日
    浏览(44)
  • JUC并发编程学习笔记(九)阻塞队列

    阻塞 队列 队列的特性:FIFO(fist inpupt fist output)先进先出 不得不阻塞的情况 什么情况下会使用阻塞队列:多线程并发处理、线程池 学会使用队列 添加、移除 四组API 方式 抛出异常 不抛出异常,有返回值 阻塞等待 超时等待 添加 add offer put offer(E e, long timeout, TimeUnit unit) 移

    2024年02月06日
    浏览(37)
  • 【JUC进阶】09. 关于锁升级

    目录 1、前言 2、回顾 2.1、对象头和内存布局 2.2、四大锁回顾 3、状态转换 3.1、锁状态 3.1.1、无锁状态 3.1.2、偏向锁状态 3.1.3、轻量级锁状态 3.1.4、重量级锁状态 3.2、状态转换条件 3.2.1、无锁 - 偏向锁 3.2.2、偏向锁 - 无锁 3.2.3、偏向锁 - 轻量级锁 3.2.4、轻量级锁 - 重量级锁

    2024年02月12日
    浏览(25)
  • java高并发系列 - 第25天:掌握JUC中的阻塞队列

    这是java高并发系列第25篇文章。 环境:jdk1.8。 本文内容 掌握Queue、BlockingQueue接口中常用的方法 介绍6中阻塞队列,及相关场景示例 重点掌握4种常用的阻塞队列 Queue接口 队列是一种先进先出(FIFO)的数据结构,java中用Queue接口来表示队列。 Queue接口中定义了6个方法:

    2024年02月14日
    浏览(30)
  • JUC之线程、线程池

    start方法开启一个新线程,异步执行。 run方法同步执行,不会产生新的线程。 start方法只能执行一次,run方法可以执行多次。 sleep() 线程睡眠 两种方式调用: 线程打断 interrupt()这种方式打断,线程会抛出InterruptedException异常。比如在线程睡眠的时候,调用interrupt(),线程抛出

    2024年04月27日
    浏览(27)
  • 多线程的优点是什么?如何创建和启动一个线程?线程的状态有哪些?什么是线程安全?

    多线程的优点包括: 提高程序的执行效率:多线程可以同时执行多个任务,充分利用CPU资源,提高程序的整体执行效率。 提高系统的响应速度:多线程可以将耗时的任务放在后台执行,使得用户界面保持流畅,提高系统的响应速度。 提高系统的可靠性:多线程可以将任务分

    2024年02月15日
    浏览(50)
  • 多线程---JUC

    JUC是:java.util.concurrent这个包名的缩写。它里面包含了与并发相关,即与多线程相关的很多东西。我们下面就来介绍这些东西。 Callable接口类似与Runnable接口: Runnable接口:描述的任务是不带返回值的。 callable接口:描述的任务是带返回值的,存在的意义就是让我们获取到结果

    2024年02月07日
    浏览(27)
  • 多线程(进阶三:JUC)

    目录 一、Callable接口 1、创建线程的操作 2、编写多线程代码 (1)实现Runnable接口(使用匿名内部类) (2)实现Callable接口(使用匿名内部类) 二、ReentrantLock 1、ReentrantLock和synchronized的区别 2、如何选择使用哪个锁? 三、原子类 四、线程池 五、信号量 Semaphore 代码示例 六、

    2024年02月20日
    浏览(24)
  • 5.多线程之JUC并发编程2

    1.CompletableFuture异步回调 像ajax,未来再得到执行结果,想服务器不分先后顺序执行,可以用异步回调 2.JMM 面试:对 Volatile的理解 答: Volatile是jvm通过轻量级的同步机制,比sychronized更轻 1.保证可见性 2.不保证原子性 3.禁止指令重排 什么是JMM? 答:java内存模型,是一种规定,不存在的东西

    2024年02月08日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包