欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java并发编程系列之LockSupport的用法

程序员文章站 2022-06-26 09:59:09
目录1、什么是locksupport?2、两类基本api3、locksupport本质4、locksupport例子5、locksupport源码总结1、什么是locksupport?...

1、什么是locksupport?

locksupport是用于创建锁和其他同步类的基本线程阻塞原语

2、两类基本api

locksupport提供了两类最基本的api:

block线程类:一般都是以pack开头的方法名,pack*(...)

pack方法有两个重载的版本:blocker是一个对象,用于指定阻塞哪个对象。不知道的情况,默认以锁对象自己this为blocker

public static void park();
public static void park(object blocker);

拓展parknanos函数

public static void parknanos(object blocker, long nanos) {
    if (nanos > 0) { 
        // 获取当前线程
        thread t = thread.currentthread();
        // 设置blocker
        setblocker(t, blocker);
        // 获取许可,并设置了时间
        unsafe.park(false, nanos);
        // 设置许可,重新设置blocker为null,避免unpack,获取的blocker为之前设置的
        setblocker(t, null);
    }
}

nanos参数表示相对时间,表示等待多长时间

parkuntil函数:表示在指定的时限前禁用当前线程,deadline参数表示绝对时间,表示指定的时间

public static void parkuntil(object blocker, long deadline) {
    // 获取当前线程
    thread t = thread.currentthread();
    // 设置blocker
    setblocker(t, blocker);
    unsafe.park(true, deadline);
    // 设置blocker为null
    setblocker(t, null);
}

unblock线程类:unpack(thread)

unpack方法用于释放许可,指定线程可以继续运行。

3、locksupport本质

locksupport是一个许可的信号量机制,pack消费,unpack放入,放入也是仅一个,不累计。例如,调用unpack放入一个信号量,多次调用,这个是不会累计信号量的,pack调用之后会消费

4、locksupport例子

例子:如何控制两个线程依次打印1、2、3、4、5、6、…

import java.util.concurrent.locks.locksupport;
public class locksupportexample {
    private static final int total = 10;
    private  static int i = 0;
    static thread t1 , t2;
    public static void main(string[] args) {
        t1 = new thread(() ->{
            while (i < total) {
                system.out.println("t1:" + (++i));
                locksupport.unpark(t2);
                locksupport.park();
            }
        });
        t2 = new thread(() -> {
            while (i < total) {
                locksupport.park();
                system.out.println("t2:" + (++i));
                locksupport.unpark(t1);
            }
        });
        t1.start();
        t2.start();
    }
}

打印:

t1: 1
t2: 2
t1:3
t2:4
t1:5
t2:6
t1:7
t2:8
t1:9
t2:10

5、locksupport源码

public class locksupport {
    // hotspot implementation via intrinsics api
    private static final sun.misc.unsafe unsafe;
    private static final long parkblockeroffset;
    private static final long seed;
    private static final long probe;
    private static final long secondary;
    static {
        try {
            // 获取unsafe实例
            unsafe = sun.misc.unsafe.getunsafe();
            // 线程类的class对象
            class<?> tk = thread.class;
            // 获取thread的parkblocker字段的内存偏移地址
            parkblockeroffset = unsafe.objectfieldoffset
                (tk.getdeclaredfield("parkblocker"));
            // 获取thread的threadlocalrandomseed字段的内存偏移地址
            seed = unsafe.objectfieldoffset
                (tk.getdeclaredfield("threadlocalrandomseed"));
            // 获取thread的threadlocalrandomprobe字段的内存偏移地址
            probe = unsafe.objectfieldoffset
                (tk.getdeclaredfield("threadlocalrandomprobe"));
            // 获取thread的threadlocalrandomsecondaryseed字段的内存偏移地址
            secondary = unsafe.objectfieldoffset
                (tk.getdeclaredfield("threadlocalrandomsecondaryseed"));
        } catch (exception ex) { throw new error(ex); }
    }
}

pack方法的源码:

public static void park(object blocker) {
    // 获取当前线程
    thread t = thread.currentthread();
    // 设置blocker
    setblocker(t, blocker);
    // 获取许可
    unsafe.park(false, 0l);
    // 重新可运行后再此设置blocker为null,避免unpack获取到上一个设置的setblocker(t, blocker);
    setblocker(t, null);
}

unpack的源码:

public static void unpark(thread thread) {
    if (thread != null) // 线程为不空
        unsafe.unpark(thread); // 释放该线程许可
}

可以看出,不管是pack的源码还是unpack的源码都是通过unsafe的底层api实现的

sun.misc.unsafe可以直接进行底层非安全操作的工具类

主要提供如下操作:

  • 线程挂起与恢复
  • cas操作
  • 操纵对象属性
  • 操纵数组元素
  • 直接操纵内存

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!

相关标签: Java LockSupport