返回顶部
首页 > 资讯 > 精选 >Java多线程怎么显示锁和内置锁
  • 776
分享到

Java多线程怎么显示锁和内置锁

java 2023-05-30 21:05:19 776人浏览 薄情痞子
摘要

这篇文章主要介绍Java多线程怎么显示锁和内置锁,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算

这篇文章主要介绍Java多线程怎么显示和内置锁,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算是互有补充,这篇文章就是做一个总结

*Synchronized*

内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁。

synchronized(list){ //获得锁  list.append();  list.count();}//释放锁

通信

与Synchronized配套使用的通信方法通常有wait(),notify()。

wait()方法会立即释放当前锁,并进入等待状态,等待到相应的notify并重新获得锁过后才能继续执行;notify()不会立刻立刻释放锁,必须要等notify()所在线程执行完synchronized块中的所有代码才会释放。用如下代码来进行验证:

public static void main(String[] args){List list = new LinkedList();Thread r = new Thread(new ReadList(list));Thread w = new Thread(new WriteList(list));r.start();w.start();}class ReadList implements Runnable{private List list;public ReadList(List list){this.list = list;}@Override  public void run(){System.out.println("ReadList begin at "+System.currentTimeMillis());synchronized (list){try {Thread.sleep(1000);System.out.println("list.wait() begin at "+System.currentTimeMillis());list.wait();System.out.println("list.wait() end at "+System.currentTimeMillis());}catch (InterruptedException e) {e.printStackTrace();}}System.out.println("ReadList end at "+System.currentTimeMillis());}}class WriteList implements Runnable{private List list;public WriteList(List list){this.list = list;}@Override  public void run(){System.out.println("WriteList begin at "+System.currentTimeMillis());synchronized (list){System.out.println("get lock at "+System.currentTimeMillis());list.notify();System.out.println("list.notify() at "+System.currentTimeMillis());try {Thread.sleep(2000);}catch (InterruptedException e) {e.printStackTrace();}System.out.println("get out of block at "+System.currentTimeMillis());}System.out.println("WriteList end at "+System.currentTimeMillis());}}

运行结果:

ReadList begin at 1493650526582WriteList begin at 1493650526582list.wait() begin at 1493650527584get lock at 1493650527584list.notify() at 1493650527584get out of block at 1493650529584WriteList end at 1493650529584list.wait() end at 1493650529584ReadList end at 1493650529584

可见读线程开始运行,开始wait过后,写线程才获得锁;写线程走出同步块而不是notify过后,读线程才wait结束,亦即获得锁。所以notify不会释放锁,wait会释放锁。值得一提的是,notifyall()会通知等待队列中的所有线程。

编码

编码模式比较简单,单一,不必显示的获得锁,释放锁,能降低因粗心忘记释放锁的错误。使用模式如下:

synchronized(object){  }

灵活性

内置锁在进入同步块时,采取的是无限等待的策略,一旦开始等待,就既不能中断也不能取消,容易产生饥饿与死锁的问题
2.在线程调用notify方法时,会随机选择相应对象的等待队列的一个线程将其唤醒,而不是按照FIFO的方式,如果有强烈的公平性要求,比如FIFO就无法满足

性能

Synchronized在jdk1.5及之前性能(主要指吞吐率)比较差,扩展性也不如ReentrantLock。但是JDK1.6以后,修改了管理内置锁的算法,使得Synchronized和标准的ReentrantLock性能差别不大。

*ReentrantLock*

ReentrantLock是显示锁,需要显示进行 lock 以及 unlock 操作。

通信

与ReentrantLock搭配的通行方式是Condition,如下:

private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); condition.await();//this.wait(); condition.signal();//this.notify(); condition.signalAll();//this.notifyAll();

Condition是被绑定到Lock上的,必须使用lock.newCondition()才能创建一个Condition。从上面的代码可以看出,Synchronized能实现的通信方式,Condition都可以实现,功能类似的代码写在同一行中。而Condition的优秀之处在于它可以为多个线程间建立不同的Condition,比如对象的读/写Condition,队列的空/满Condition,在JDK源码中的ArrayBlockingQueue中就使用了这个特性:

public ArrayBlockingQueue(int capacity, boolean fair) {  if (capacity <= 0)    throw new IllegalArgumentException();  this.items = new Object[capacity];  lock = new ReentrantLock(fair);  notEmpty = lock.newCondition();  notFull = lock.newCondition();}public void put(E e) throws InterruptedException {  checkNotNull(e);  final ReentrantLock lock = this.lock;  lock.lockInterruptibly();  try {    while (count == items.length)      notFull.await();    enqueue(e);  } finally {    lock.unlock();  }}public E take() throws InterruptedException {  final ReentrantLock lock = this.lock;  lock.lockInterruptibly();  try {    while (count == 0)      notEmpty.await();    return dequeue();  } finally {    lock.unlock();  }}private void enqueue(E x) {  // assert lock.getHoldCount() == 1;  // assert items[putIndex] == null;  final Object[] items = this.items;  items[putIndex] = x;  if (++putIndex == items.length)    putIndex = 0;  count++;  notEmpty.signal();}private E dequeue() {  // assert lock.getHoldCount() == 1;  // assert items[takeIndex] != null;  final Object[] items = this.items;  @SuppressWarnings("unchecked")  E x = (E) items[takeIndex];  items[takeIndex] = null;  if (++takeIndex == items.length)    takeIndex = 0;  count--;  if (itrs != null)    itrs.elementDequeued();  notFull.signal();  return x;}

编码

Lock lock = new ReentrantLock();lock.lock();try{ }finally{  lock.unlock();}

相比于Synchronized要复杂一些,而且一定要记得在finally中释放锁而不是其他地方,这样才能保证即使出了异常也能释放锁。

灵活性

lock.lockInterruptibly()可以使得线程在等待锁是支持响应中断;lock.tryLock()可以使得线程在等待一段时间过后如果还未获得锁就停止等待而非一直等待。有了这两种机制就可以更好的制定获得锁的重试机制,而非盲目一直等待,可以更好的避免饥饿和死锁问题

ReentrantLock可以成为公平锁(非默认的),所谓公平锁就是锁的等待队列的FIFO,不过公平锁会带来性能消耗,如果不是必须的不建议使用。这和CPU对指令进行重排序的理由是相似的,如果强行的按照代码的书写顺序来执行指令,就会浪费许多时钟周期,达不到最大利用率

性能

虽然Synchronized和标准的ReentrantLock性能差别不大,但是ReentrantLock还提供了一种非互斥的读写锁,

也就是不强制每次最多只有一个线程能持有锁,它会避免“读/写”冲突,“写/写”冲突,但是不会排除“读/读”冲突,

因为“读/读”并不影响数据的完整性,所以可以多个读线程同时持有锁,这样在读写比较高的情况下,性能会有很大的提升。

下面用两种锁分别实现的线程安全的linkedlist:

class RWLockList {//读写锁private List list;private final ReadWriteLock lock = new ReentrantReadWriteLock();private final Lock readLock = lock.readLock();private final Lock writeLock = lock.writeLock();public RWLockList(List list){this.list = list;}public int get(int k) {readLock.lock();try {return (int)list.get(k);}finally {readLock.unlock();}}public void put(int value) {writeLock.lock();try {list.add(value);}finally {writeLock.unlock();}}}class SyncList {private List list;public SyncList(List list){this.list = list;}public synchronized int get(int k){return (int)list.get(k);}public synchronized void put(int value){list.add(value);}}

读写锁测试代码:

List list = new LinkedList();for (int i=0;i<10000;i++){list.add(i);}RWLockList rwLockList = new RWLockList(list);//初始化数据Thread writer = new Thread(new Runnable() {@Override  public void run() {for (int i=0;i<10000;i++){rwLockList.put(i);}}});Thread reader1 = new Thread(new Runnable() {@Override  public void run() {for (int i=0;i<10000;i++){rwLockList.get(i);}}});Thread reader2 = new Thread(new Runnable() {@Override  public void run() {for (int i=0;i<10000;i++){rwLockList.get(i);}}});long begin = System.currentTimeMillis();writer.start();reader1.start();reader2.start();try {writer.join();reader1.join();reader2.join();}catch (InterruptedException e) {e.printStackTrace();}System.out.println("RWLockList take "+(System.currentTimeMillis()-begin) + "ms");

同步锁测试代码:

List list = new LinkedList();for (int i=0;i<10000;i++){  list.add(i);}SyncList syncList = new SyncList(list);//初始化数据Thread writerS = new Thread(new Runnable() {  @Override  public void run() {    for (int i=0;i<10000;i++){      syncList.put(i);    }  }});Thread reader1S = new Thread(new Runnable() {  @Override  public void run() {    for (int i=0;i<10000;i++){      syncList.get(i);    }  }});Thread reader2S = new Thread(new Runnable() {  @Override  public void run() {    for (int i=0;i<10000;i++){      syncList.get(i);    }  }});long begin1 = System.currentTimeMillis();writerS.start();reader1S.start();reader2S.start();try {  writerS.join();  reader1S.join();  reader2S.join();} catch (InterruptedException e) {  e.printStackTrace();}System.out.println("SyncList take "+(System.currentTimeMillis()-begin1) + "ms");

结果:

RWLockList take 248msRWLockList take 255msRWLockList take 249msRWLockList take 224ms SyncList take 351msSyncList take 367msSyncList take 315msSyncList take 323ms

可见读写锁的确是优于纯碎的互斥锁

以上是“Java多线程怎么显示锁和内置锁”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: Java多线程怎么显示锁和内置锁

本文链接: https://lsjlt.com/news/221344.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java多线程怎么显示锁和内置锁
    这篇文章主要介绍Java多线程怎么显示锁和内置锁,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算...
    99+
    2023-05-30
    java
  • Java多线程的内置锁与显示锁介绍
    这篇文章主要讲解了“Java多线程的内置锁与显示锁介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程的内置锁与显示锁介绍”吧!Synchronized内置锁获得锁和释放锁是隐式...
    99+
    2023-06-17
  • 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)
    synchronized 和 Reentrantlock多线程编程中,当代码需要同步时我们会用到锁。Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式。显式锁是JDK1.5引入的,这两种...
    99+
    2023-05-30
    java 内置锁 synchronized
  • # Python 多线程和锁
    作者博客:http://zzir.cn/ 进程和线程 进程是执行中的计算机程序。每个进程都拥有自己的地址空间、内存、数据栈及其它的辅助数据。操作系统管理着所有的进程,并为这些进程合理分配时间。进程可以通过派生新的进程来执行其它任务,不过...
    99+
    2023-01-31
    多线程 Python
  • Java多线程之锁怎么使用
    本篇内容介绍了“Java多线程之锁怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!首先强调一点:Java多线程的锁都是基于对象的,Ja...
    99+
    2023-07-05
  • Java多线程之悲观锁与乐观锁
    目录1. 悲观锁存在的问题2. 通过CAS实现乐观锁3. 不可重入的自旋锁4. 可重入的自旋锁总结问题: 1、乐观锁和悲观锁的理解及如何实现,有哪些实现方式? 2、什么是乐观锁和悲观...
    99+
    2024-04-02
  • Java多线程(3)---锁策略、CAS和JUC
    目录 前言 一.锁策略 1.1乐观锁和悲观锁 ⭐ 两者的概念 ⭐实现方法 1.2读写锁  ⭐概念 ⭐实现方法 1.3重量级锁和轻量级锁 1.4自旋锁和挂起等待锁 ⭐概念 ⭐代码实现 1.5公平锁和非公平锁 1.6可重入锁和不可重入锁 二.C...
    99+
    2023-08-31
    开发语言 多线程 java-ee
  • Java多线程之死锁的示例分析
    小编给大家分享一下Java多线程之死锁的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!什么是死锁死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全...
    99+
    2023-05-30
    java
  • C#多线程锁lock和Monitor怎么用
    本文小编为大家详细介绍“C#多线程锁lock和Monitor怎么用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C#多线程锁lock和Monitor怎么用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1,Loc...
    99+
    2023-06-29
  • Java多线程之多种锁和阻塞队列
    目录一、悲观锁和乐观锁1.1. 乐观锁1.2. 悲观锁二、公平锁和非公平锁三、可重入锁(递归锁)四、自旋锁五、独占锁(写)/共享锁(读)六、什么是阻塞队列?七、阻塞队列(Blocki...
    99+
    2024-04-02
  • Java多线程死锁问题怎么解决
    解决Java多线程死锁问题的常用方法有以下几种:1. 避免使用多个锁:尽量减少使用多个锁来降低出现死锁的概率。2. 按照固定的顺序获...
    99+
    2023-09-22
    Java
  • Java多线程之死锁问题,wait和notify
    文章目录 一. synchronnized 的特性1. 互斥性2. 可重入性 二. 死锁问题1. 什么是死锁2. 死锁的四个必要条件3. 常见的死锁场景及解决3.1 不可重入造成的死锁3....
    99+
    2023-09-13
    java 死锁 wait notify synchronized
  • Java多线程之多种锁和阻塞队列的示例分析
    这篇文章给大家分享的是有关Java多线程之多种锁和阻塞队列的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、悲观锁和乐观锁1.1. 乐观锁顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以...
    99+
    2023-06-15
  • Java多线程之死锁详解
    目录1、死锁2、死锁经典问题——哲学家就餐问题 总结1、死锁 出现场景:当线程A拥有了A对象的锁,想要去获取B对象的锁;线程B拥有了B对象的锁,想要拥有A对象的锁,两个线程...
    99+
    2024-04-02
  • java线程死锁代码示例
    死锁是操作系统层面的一个错误,是进程死锁的简称,最早在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。事实上,计算机世界有很多事情需要多线程方式去解决,因为这样才能...
    99+
    2023-05-30
    java 线程 死锁
  • 如何使用多线程和锁
    本篇内容介绍了“如何使用多线程和锁”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、前言你只面向工作学习吗...
    99+
    2024-04-02
  • C#多线程系列之多线程锁lock和Monitor
    目录1,Locklock 原型lock 编写实例2,Monitor怎么用呢解释一下示例设置获取锁的时效1,Lock lock 用于读一个引用类型进行加锁,同一时刻内只有一个线程能够访...
    99+
    2024-04-02
  • Java多线程 乐观锁和CAS机制详细
    目录一、悲观锁和乐观锁1、悲观锁2、乐观锁二、CAS机制一、悲观锁和乐观锁 1、悲观锁 悲观锁是基于一种悲观的态度类来防止一切数据冲突,它是以一种预防的姿态在修改数据之前把数据锁住,...
    99+
    2024-04-02
  • Java多线程死锁问题详解(wait和notify)
    目录一. synchronnized 的特性1. 互斥性2. 可重入性二. 死锁问题1. 什么是死锁2. 死锁的四个必要条件3. 常见的死锁场景及解决3.1 不可重入造成的死锁3.2...
    99+
    2023-01-05
    Java多线程死锁 java死锁的原因及解决方法 java多线程死锁问题
  • java多线程死锁如何解决
    Java中死锁的解决办法有以下几种:1. 避免使用多个锁:当多个线程需要获取多个锁时,可以尝试将多个锁合并为一个锁,或者将一个锁拆分...
    99+
    2023-08-24
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作