博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发编程(十五)-LockSupport工具类
阅读量:2203 次
发布时间:2019-05-03

本文共 4253 字,大约阅读时间需要 14 分钟。

LockSupport是Java6引入的一个工具类,它简单灵活,应用广泛。

一、简单 

俗话说,没有比较就没有伤害。这里咱们还是通过对比来介绍LockSupport的简单。

在没有LockSupport之前,线程的挂起和唤醒咱们都是通过Object的wait和notify/notifyAll方法实现。

写一段例子代码,线程A执行一段业务逻辑后调用wait阻塞住自己。主线程调用notify方法唤醒线程A,线程A然后打印自己执行的结果。

public class TestObjWait {    public static void main(String[] args)throws Exception {        final Object obj = new Object();        Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                try {                    obj.wait();                }catch (Exception e){                    e.printStackTrace();                }                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法        Thread.sleep(1000);        obj.notify();    }}

执行这段代码,不难发现这个错误:

Exception in thread "main" java.lang.IllegalMonitorStateException    at java.lang.Object.notify(Native Method)

原因很简单,wait和notify/notifyAll方法只能在同步代码块里用(这个有的面试官也会考察)。所以将代码修改为如下就可正常运行了:

public class TestObjWait {    public static void main(String[] args)throws Exception {        final Object obj = new Object();        Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                try {                    synchronized (obj){                        obj.wait();                    }                }catch (Exception e){                    e.printStackTrace();                }                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法        Thread.sleep(1000);        synchronized (obj){            obj.notify();        }    }}

那如果咱们换成LockSupport呢?简单得很,看代码:

public class TestObjWait {    public static void main(String[] args)throws Exception {        Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                LockSupport.park();                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法        Thread.sleep(1000);        LockSupport.unpark(A);    }}
直接调用就可以了,没有说非得在同步代码块里才能用。简单吧。

二、灵活

如果只是LockSupport在使用起来比Object的wait/notify简单,那还真没必要专门讲解下LockSupport。最主要的是灵活性。

上边的例子代码中,主线程调用了Thread.sleep(1000)方法来等待线程A计算完成进入wait状态。如果去掉Thread.sleep()调用,代码如下:

public class TestObjWait {    public static void main(String[] args)throws Exception {        final Object obj = new Object();        Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                try {                    synchronized (obj){                        obj.wait();                    }                }catch (Exception e){                    e.printStackTrace();                }                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法        //Thread.sleep(1000);        synchronized (obj){            obj.notify();        }    }}

多运行几次上边的代码,有的时候能够正常打印结果并退出程序,但有的时候线程无法打印结果阻塞住了。原因就在于:主线程调用完notify后,线程A才进入wait方法,导致线程A一直阻塞住。由于线程A不是后台线程,所以整个程序无法退出。

那如果换做LockSupport呢?LockSupport就支持主线程先调用unpark后,线程A再调用park而不被阻塞吗?是的,没错。代码如下:

public class TestObjWait {    public static void main(String[] args)throws Exception {        final Object obj = new Object();        Thread A = new Thread(new Runnable() {            @Override            public void run() {                int sum = 0;                for(int i=0;i<10;i++){                    sum+=i;                }                LockSupport.park();                System.out.println(sum);            }        });        A.start();        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法        //Thread.sleep(1000);        LockSupport.unpark(A);    }}

不管你执行多少次,这段代码都能正常打印结果并退出。这就是LockSupport最大的灵活所在。

 

总结一下,LockSupport比Object的wait/notify有两大优势

①LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。

②unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。

转载地址:http://yayyb.baihongyu.com/

你可能感兴趣的文章
用线性判别分析 LDA 降维
查看>>
用 Doc2Vec 得到文档/段落/句子的向量表达
查看>>
使聊天机器人具有个性
查看>>
使聊天机器人的对话更有营养
查看>>
一个 tflearn 情感分析小例子
查看>>
attention 机制入门
查看>>
手把手用 IntelliJ IDEA 和 SBT 创建 scala 项目
查看>>
GAN 的 keras 实现
查看>>
AI 在 marketing 上的应用
查看>>
Logistic regression 为什么用 sigmoid ?
查看>>
Logistic Regression 为什么用极大似然函数
查看>>
SVM 的核函数选择和调参
查看>>
LightGBM 如何调参
查看>>
用 TensorFlow.js 在浏览器中训练神经网络
查看>>
cs230 深度学习 Lecture 2 编程作业: Logistic Regression with a Neural Network mindset
查看>>
梯度消失问题与如何选择激活函数
查看>>
为什么需要 Mini-batch 梯度下降,及 TensorFlow 应用举例
查看>>
为什么在优化算法中使用指数加权平均
查看>>
什么是 Q-learning
查看>>
用一个小游戏入门深度强化学习
查看>>