iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java并发之同步器设计的方法是什么
  • 325
分享到

Java并发之同步器设计的方法是什么

2023-06-16 11:06:55 325人浏览 薄情痞子
摘要

本篇内容介绍了“java并发之同步器设计的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在 Java并发之内存模型了解到多进程(线

本篇内容介绍了“java并发之同步器设计的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

在 Java并发之内存模型了解到多进程(线程)读取共享资源的时候存在竞争条件。

Java并发之同步器设计的方法是什么

计算机中通过设计同步器来协调进程(线程)之间执行顺序。同步器作用就像登机安检人员一样可以协调旅客按顺序通过。

在Java中,同步器可以理解为一个对象,它根据自身状态协调线程的执行顺序。比如(Lock),信号量(Semaphore),屏障(CyclicBarrier),阻塞队列(Blocking Queue)。

这些同步器在功能设计上有所不同,但是内部实现上有共通的地方。

同步器

同步器的设计一般包含几个方面:状态变量设计(同步器内部状态),访问条件设定,状态更新,等待方式,通知策略。

Java并发之同步器设计的方法是什么

访问条件是控制线程是否能执行(访问共享对象)的条件,它往往与状态变量紧密相关。而通知策略是线程释放锁定状态后通知其它等待线程的方式,一般有以下几种情况

  •  通知所有等待的线程。

  •  通知1个随机的N个等待线程。

  •  通知1个特定的N个等待线程

看下面例子,通过锁方式的同步器

public class Lock{    // 状态变量 isLocked    private boolean isLocked = false;    public synchronized void lock() throws InterruptedException{      // 访问条件 当isLocked=false 时获得访问权限否则等待      while(isLocked){        // 阻塞等待        wait();      }      //状态更新 线程获得访问权限      isLocked = true;    }    public synchronized void unlock(){      //状态更新 线程释放访问权限      isLocked = false;      // 通知策略 object.notify | object.notifyAll      notify();     }  }

我们用计数信号量控制同时执行操作活动数。这里模拟一个连接池。

public class PoolSemaphore {        // 状态变量 actives 计数器      private int actives = 0;      private int max;      public PoolSemaphore(int max) {          this.max = max;      }      public synchronized void acquire() throws InterruptedException {          //访问条件 激活数小于最大限制时,获得访问权限否则等待          while (this.actives == max) wait();          //状态更新 线程获得访问权限          this.actives++;          // 通知策略 object.notify | object.notifyAll          this.notify();      }      public synchronized void release() throws InterruptedException {          //访问条件 激活数不为0时,获得访问权限否则等待          while (this.actives == 0) wait();           //状态更新 线程获得访问权限          this.actives--;          // 通知策略 object.notify | object.notifyAll          this.notify();      }  }

原子指令

同步器设计里面,最重要的操作逻辑是“如果满足条件,以更新状态变量来标志线程获得或释放访问权限”,该操作应具备原子性。

比如test-and-set 计算机原子指令,意思是进行条件判断满足则设置新值。

function Lock(boolean *lock) {       while (test_and_set(lock) == 1);   }

另外还有很多原子指令 fetch-and-add compare-and-swap,注意这些指令需硬件支持才有效。

同步操作中,利用计算机原子指令,可以避开锁,提升效率。java中没有 test-and-set 的支持,不过 java.util.concurrent.atomic 给我们提供了很多原子类api,里面支持了 getAndSet 和compareAndSet 操作。

看下面例子,主要在区别是等待方式不一样,上面是通过wait()阻塞等待,下面是无阻塞循环。

public class Lock{    // 状态变量 isLocked    private AtomicBoolean isLocked = new AtomicBoolean(false);    public void lock() throws InterruptedException{      // 等待方式 变为自旋等待      while(!isLocked.compareAndSet(false, true));      //状态更新 线程获得访问权限      isLocked.set(true);    }    public synchronized void unlock(){      //状态更新 线程释放访问权限      isLocked.set(false);    }  }

关于阻塞扩展说明

阻塞意味着需要将进程或线程状态进行转存,以便还原后恢复执行。这种操作是昂贵繁重,而线程基于进程之上相对比较轻量。线程的阻塞在不同编程平台实现方式也有所不同,像Java是基于JVM运行,所以它由JVM完成实现。

在《Java Concurrency in Practice》中,作者提到

竞争性同步可能需要OS活动,这增加了成本。当争用锁时,未获取锁的线程必须阻塞。 JVM可以通过旋转等待(反复尝试获取锁直到成功)来实现阻塞,也可以通过操作系统挂起阻塞的线程来实现阻塞。哪种效率更高取决于上下文切换开销与锁定可用之前的时间之间的关系。对于短暂的等待,最好使用自旋等待;对于长时间的等待,最好使用暂停。一些JVM基于对过去等待时间的分析数据来自适应地在这两者之间进行选择,但是大多数JVM只是挂起线程等待锁定。

从上面可以看出JVM实现阻塞两种方式

  •  旋转等待(spin-waiting),简单理解是不暂停执行,以循环的方式等待,适合短时间场景。

  •  通过操作系统挂起线程。

JVM中通过 -XX: +UseSpinning 开启旋转等待, -XX: PreBlockSpi =10指定最大旋转次数。

Java并发之同步器设计的方法是什么

AQS

AQS是AbstractQueuedSynchronizer简称。本节对AQS只做简单阐述,并不全面。

java.util.concurrent包中的 ReentrantLock,CountDownLatch,Semaphore,CyclicBarrier等都是基于是AQS同步器实现。

状态变量 是用 int state 来表示,状态的获取与更新通过以下API操作。   

int getState()      void setState(int newState)      boolean compareAndSetState(int expect, int update)

该状态值在不同API中有不同表示意义。比如ReentrantLock中表示持有锁的线程获取锁的次数,Semaphore表示剩余许可数。

关于等待方式和通知策略的设计

AQS通过维护一个FIFO同步队列(Sync queue)来进行同步管理。当多线程争用共享资源时被阻塞入队。而线程阻塞与唤醒是通过 LockSupport.park/unpark API实现。

它定义了两种资源共享方式。

  •  Exclusive(独占,只有一个线程能执行,如ReentrantLock)

  •  Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)

每个节点包含waitStatus(节点状态),prev(前继),next(后继),thread(入队时线程),nextWaiter(condition队列的后继节点)

Java并发之同步器设计的方法是什么

waitStatus 有以下取值。

  •  CANCELLED(1) 表示线程已取消。当发生超时或中断,节点状态变为取消,之后状态不再改变。

  •  SIGNAL(-1) 表示后继节点等待前继的唤醒。后继节点入队时,会将前继状态更新为SIGNAL。

  •  CONDITION(-2) 表示线程在Condition queue 里面等待。当其他线程调用了Condition.signal()方法后,CONDITION状态的节点将从 Condition queue 转移到 Sync queue,等待获取锁。

  •  PROPAGATE(-3) 在共享模式下,当前节点释放后,确保有效通知后继节点。

  •  (0) 节点加入队列时的默认状态。

AQS 几个关键 API

  •  tryAcquire(int) 独占方式下,尝试去获取资源。成功返回true,否则false。

  •  tryRelease(int) 独占方式下,尝试释放资源,成功返回true,否则false。

  •  tryAcquireShared(int) 共享方式下,尝试获取资源。返回负数为失败,零和正数为成功并表示剩余资源。

  •  tryReleaseShared(int) 共享方式下,尝试释放资源,如果释放后允许唤醒后续等待节点返回true,否则false。

  •  isHeldExclusively() 判断线程是否正在独占资源。

acquire(int arg) 

public final void acquire(int arg) {          if (            // 尝试直接去获取资源,如果成功则直接返回            !tryAcquire(arg)              &&              //线程阻塞在同步队列等待获取资源。等待过程中被中断,则返回true,否则false              acquireQueued(                // 标记该线程为独占方式,并加入同步队列尾部。                addWaiter(node.EXCLUSIVE), arg)              )              selfInterrupt();      }

release(int arg) 

public final boolean release(int arg) {           // 尝试释放资源         if (tryRelease(arg)) {             Node h = head;             if (h != null && h.waitStatus != 0)               // 唤醒下一个线程(后继节点)               unparkSuccessor(h);             return true;         }         return false;     }
private void unparkSuccessor(Node node) {          ....                Node s = node.next; // 找到后继节点          if (s == null || s.waitStatus > 0) {//无后继或节点已取消              s = null;             // 找到有效的等待节点               for (Node t = tail; t != null && t != node; tt = t.prev)                  if (t.waitStatus <= 0)                      s = t;          }          if (s != null)              LockSupport.unpark(s.thread); // 唤醒     }

“Java并发之同步器设计的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Java并发之同步器设计的方法是什么

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java并发之同步器设计的方法是什么
    本篇内容介绍了“Java并发之同步器设计的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在 Java并发之内存模型了解到多进程(线...
    99+
    2023-06-16
  • 浅谈Java并发之同步器设计
    前言: 在 Java并发内存模型详情了解到多进程(线程)读取共享资源的时候存在竞争条件。 计算机中通过设计同步器来协调进程(线程)之间执行顺序。同步器作用就像登机安检人员一样可以协...
    99+
    2024-04-02
  • Java并发代码设计的步骤是什么
    这篇文章主要介绍“Java并发代码设计的步骤是什么”,在日常操作中,相信很多人在Java并发代码设计的步骤是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java并发代码设计的步骤是什么”的疑惑有所帮助!...
    99+
    2023-06-17
  • Java并发编程之同步容器
    目录简介一、什么是同步容器二、为什么要有同步容器三、同步容器的优缺点四、同步容器的使用场景总结简介 同步容器主要分两类,一种是Vector这样的普通类,一种是通过Collection...
    99+
    2024-04-02
  • java异步转同步的方法是什么
    Java中实现异步转同步的方法有多种,下面列举了几种常用的方法。 使用CountDownLatch: CountDownLatch...
    99+
    2023-10-24
    java
  • Java并发编程之同步容器与并发容器详解
    一、同步容器  1、Vector——>ArrayList  vector 是线程(Thread)同步(Synchronized)的,所以它也是线程...
    99+
    2024-04-02
  • java并发编程之同步器代码示例
    同步器是一些使线程能够等待另一个线程的对象,允许它们协调动作。最常用的同步器是CountDownLatch和Semaphore,不常用的是Barrier和Exchanger队列同步器AbstractQueuedSynchronizer是用来...
    99+
    2023-05-30
    java 并发 同步器
  • Java并发编程之同步容器与并发容器的示例分析
    这篇文章主要为大家展示了“Java并发编程之同步容器与并发容器的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程之同步容器与并发容器的示例分析”这篇文章吧。一、同步容器&n...
    99+
    2023-06-15
  • MySQL触发器同步数据库的方法是什么
    MySQL触发器是一种用于在数据库中自动执行特定操作的机制。通过使用触发器,可以在数据库中的特定事件发生时自动更新或同步数据。 要在...
    99+
    2023-10-24
    mysql 数据库
  • Java泛型的设计方法是什么
    这篇文章主要讲解了“Java泛型的设计方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java泛型的设计方法是什么”吧!引言泛型是Java中一个非常重要的知识点,在Java集合类框架...
    99+
    2023-06-17
  • JAVA性能设计方法是什么
    本篇内容介绍了“JAVA性能设计方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  概要  许多通常的 Java 性能问题都起源于在...
    99+
    2023-06-03
  • OpenMP并行程序设计方法是什么
    本篇内容主要讲解“OpenMP并行程序设计方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“OpenMP并行程序设计方法是什么”吧!在VC8.0中项目的属...
    99+
    2024-04-02
  • Java并发编程同步器CountDownLatch怎么用
    今天小编给大家分享一下Java并发编程同步器CountDownLatch怎么用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。...
    99+
    2023-06-30
  • java并发处理数据的方法是什么
    Java中处理并发数据的方法有以下几种:1. 使用synchronized关键字:synchronized关键字可以用于方法或代码块...
    99+
    2023-10-11
    java
  • JAVA poi导出合并相同行的方法是什么
    在使用JAVA POI导出Excel文件时,可以使用以下步骤来合并相同行:1. 创建一个Workbook对象,例如XSSFWorkb...
    99+
    2023-10-18
    java
  • 关于sql server2012同步失效问题之高并发库同步失败的解决方法
    关于sql server2012数据库复制同步时报错:“ 该作业失败。  计划 1127 (复制代理计划。) 调用了该作业。最后运行的是步骤 1 (运行代理。)。. 已以用户 NT SE...
    99+
    2024-04-02
  • Java并发编程学习方法是什么
    这篇文章主要讲解了“Java并发编程学习方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java并发编程学习方法是什么”吧!一:并发基础和多线程首先需要学习的就是并发的基础知识,什么...
    99+
    2023-06-02
  • ubuntu同步时间的方法是什么
    本文小编为大家详细介绍“ubuntu同步时间的方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“ubuntu同步时间的方法是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.打开终端输入以下命令安装n...
    99+
    2023-07-04
  • centos时间同步的方法是什么
    本篇内容主要讲解“centos时间同步的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“centos时间同步的方法是什么”吧!安装yum install ntpdate授时服务器微软公司...
    99+
    2023-06-26
  • rabbitmq同步调用的方法是什么
    RabbitMQ是一个消息中间件,它主要用于在不同的应用程序之间传递消息。它支持异步消息传递,但不直接支持同步调用。然而,可以使用一...
    99+
    2023-10-26
    rabbitmq
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作