当前位置: 首页 > news >正文

Java多线程(三) -- Lock

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1、ReentrantLock 重入锁

ReentrantLock是Lock接口的实现类,ReentrantLock提供相对synchronized更为灵活的机制,有以下优点:

  • 使用synchronized关键字时,只能在synchronized块结构中使用wait()、notify()等获取和释放控制。而使用Lock,获取和释放可以不在同一个块结构中;
  • Lock接口提供了tryLock()方法,这个方法试图获取锁,如果锁已经被其他线程获取,它将返回false,并继续往下执行代码,而不会像synchronized一样阻塞等待。
  • 相比synchronized,Lock的性能更好
public class Test {
    public static void main(String[] args) {
        PrintQueue printQueue = new PrintQueue();
        for (int i = 0; i < 10; i++) {
            new Thread(new Job(printQueue)).start();
        }
    }
}
class  PrintQueue{
    //声明锁对象并初始化
    private final Lock queueLock = new ReentrantLock();
    public void printJob(Object document){
        //获取锁对象的控制
        queueLock.lock();
        Long duration = (long)(Math.random()*10000);
        System.out.println(duration);
        try {
            Thread.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放锁对象的控制
            queueLock.unlock();
        }
    }
}
class Job implements Runnable{
    private PrintQueue printQueue;
    public Job(PrintQueue printQueue){
        this.printQueue = printQueue;
    }

    @Override
    public void run() {
        printQueue.printJob(new Object());
    }
}

Lock接口最主要的三个方法是:

  1. lock()方法,获取锁对象的控制,如果其他线程正在占用锁,会阻塞等待
  2. unLock()方法,释放锁对象的控制,必须要进行释放,否则会造成死锁
  3. tryLock()方法,尝试获取锁,如果当前其他线程正在占用锁,不会阻塞等待而会立刻返回false

2、ReentrantReadWirteLock 重入读写锁

ReentrantReadWirteLock是ReadWriteLock接口的实现类,这个类有两个锁,一个是读操作锁,一个是写操作锁

  • 其中使用读操作锁时可以允许多个线程同时访问,但是使用写操作锁时只允许一个线程进行
  • 在一个线程执行写操作时,其他线程不能进行读操作

读写分离相对synchronized的情况大大提高了程序的效率。

使用ReentrantReadWriteLock时,主要有两个方法:

  1. readLock(),,然后可以调用lock、unLock、tryLock方法
  2. writeLock(),然后可以调用lock、unLock、tryLock方法
class PricesInfo{
    private double price1;
    private double price2;
    //读写锁
    private ReadWriteLock readWriteLock;
    public PricesInfo(){
        price1 = 1.0;
        price2 = 1.0;
        readWriteLock = new ReentrantReadWriteLock();
    }

    /**
     * 获取读锁来获取数据
     * @return
     */
    public double getPrice1(){
        //获取读锁
        readWriteLock.readLock().lock();
        double value = price1;
        //释放读锁
        readWriteLock.readLock().unlock();
        return value;
    }

    public double getPrice2(){
        readWriteLock.readLock().lock();
        double value = price2;
        readWriteLock.readLock().unlock();
        return value;
    }

    public void setPrices(double price1,double price2){
        //获取写锁
        readWriteLock.writeLock().lock();
        this.price1 = price1;
        this.price2 = price2;
        //释放写锁
        readWriteLock.writeLock().unlock();
    }
}

3、Lock的公平性

ReentrantLock和ReentrantReadWriteLock类都有一个boolean参数fair,默认值为false。

当fair = false时,为“非公平模式”,此时如果有多个线程在等待锁,锁将随机选择其中的一个线程。

当fair = true时,为“公平模式”,此时如果有多个线程在等待锁,锁将选择“已等待时间最长”的线程。

要修改fair值,只需使用重载的构造函数即可:

private Lock queueLock = new ReentrantLock(true);

4、在Lock中使用Condition的await()、signal()、signalAll()方法

Condition对象可以由Lock对象的newCondition()创建:

Lock lock = new ReentranLock();
//创建两个Condition对象
Condition con1 = lock.newCondition();
Condition con2 = lock.newCondition();

await()、signal()、signalAll()方法和Synchronized代码块中的wait()、notify()、notifyAll()方法类似,不同之处在于:

//下面这个语句只能唤醒因调用con1.await()而阻塞的线程
con1.signalAll();

//同理这个语句只能唤醒因con2.await()而阻塞的线程
con2.signalAll();

 

转载于:https://my.oschina.net/pierrecai/blog/894610

相关文章:

  • Linux下电骡aMule Kademlia网络构建分析3
  • C# List集合基础操作
  • bootstrap-表格-响应式表格
  • Linux下的ls 常用命令
  • jquery ui autocomplete 自动补充完成 测试在ie下 点击显示列表框 有时候需要多次点击才能选取值...
  • mysql 误删root
  • 数据库查询
  • 黑马程序员——Java基础语法---数组
  • Reinhold就Jigsaw投票一事向JCP提交公开信
  • eclipse快捷键调试总结 -转--快捷键大全
  • git基本操作
  • bootstrap(4)关于下拉菜单的功能
  • ASP.NET 5探险(8):利用中间件、TagHelper来在MVC 6中实现Captcha
  • 【c语言】统计一个数字在排序数组中出现的次数
  • CentOS 下安装testlink
  • emacs初体验
  • go语言学习初探(一)
  • Python3爬取英雄联盟英雄皮肤大图
  • React16时代,该用什么姿势写 React ?
  • springMvc学习笔记(2)
  • Spring框架之我见(三)——IOC、AOP
  • text-decoration与color属性
  • Unix命令
  • VUE es6技巧写法(持续更新中~~~)
  • 番外篇1:在Windows环境下安装JDK
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 理清楚Vue的结构
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 数据仓库的几种建模方法
  • 我有几个粽子,和一个故事
  • 一个SAP顾问在美国的这些年
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (2)MFC+openGL单文档框架glFrame
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (42)STM32——LCD显示屏实验笔记
  • (LeetCode C++)盛最多水的容器
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (动态规划)5. 最长回文子串 java解决
  • (二)学习JVM —— 垃圾回收机制
  • (二十三)Flask之高频面试点
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (四)库存超卖案例实战——优化redis分布式锁
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • @private @protected @public
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [] 与 [[]], -gt 与 > 的比较
  • [android] 看博客学习hashCode()和equals()
  • [Android]Android开发入门之HelloWorld
  • [Android]如何调试Native memory crash issue