第三百二十三节 Java线程教程 - Java同步器

Java线程教程 - Java同步器

同步器对象与一组线程一起使用。

它维护一个状态,根据它的状态,它让一个线程通过或强迫它等待。

本节将讨论四种类型的同步器:

  • Semaphores
  • Barriers
  • Latches
  • Exchangers

信号量

信号量用于控制可以访问资源的线程数。

java.util.concurrent包中的Semaphore类表示信号量同步器。

您可以使用其构造函数创建信号量,如下所示:

final int MAX_PERMITS  = 3;
Semaphore  s = new Semaphores(MAX_PERMITS);

Semaphore类的另一个构造函数使用公平作为第二个参数

final int MAX_PERMITS  = 3;
Semaphore  s = new Semaphores(MAX_PERMITS,  true); // A  fair  semaphore

如果你创建一个公平的信号量,在多线程请求许可的情况下,信号量将保证先进先出(FIFO)。也就是说,首先请求许可的线程将首先获得许可。

要获取许可证,请使用acquire()方法。

如果许可证可用,它立即返回。

它阻止如果许可证不可用。线程在等待许可证可用时可能中断。

Semaphore类的其他方法允许您一次性获取一个或多个许可证。要释放许可证,请使用release()方法。

以下代码显示了一个Restaurant类,它使用信号量来控制对表的访问。

import java.util.Random;
import java.util.concurrent.Semaphore;class Restaurant {private Semaphore tables;public Restaurant(int tablesCount) {this.tables = new Semaphore(tablesCount);}public void getTable(int customerID) {try {System.out.println("Customer  #" + customerID+ "  is trying  to  get  a  table.");tables.acquire();System.out.println("Customer #" + customerID + "  got  a  table.");} catch (InterruptedException e) {e.printStackTrace();}}public void returnTable(int customerID) {System.out.println("Customer #" + customerID + "  returned a  table.");tables.release();}
}
class RestaurantCustomer extends Thread {private Restaurant r;private int customerID;private static final Random random = new Random();public RestaurantCustomer(Restaurant r, int customerID) {this.r = r;this.customerID = customerID;}public void run() {r.getTable(this.customerID); // Get a tabletry {int eatingTime = random.nextInt(30) + 1;System.out.println("Customer #" + this.customerID+ "  will eat for " + eatingTime + "  seconds.");Thread.sleep(eatingTime * 1000);System.out.println("Customer #" + this.customerID+ "  is done  eating.");} catch (InterruptedException e) {e.printStackTrace();} finally {r.returnTable(this.customerID);}}
}
public class Main{public static void main(String[] args) {Restaurant restaurant = new Restaurant(2);for (int i = 1; i <= 5; i++) {RestaurantCustomer c = new RestaurantCustomer(restaurant, i);c.start();}}
}

上面的代码生成以下结果。

障碍器

屏障使一组线在屏障点汇合。

来自到达屏障的组的线程等待,直到该组中的所有线程到达。

一旦组中的最后一个线程到达屏障,组中的所有线程都将被释放。

当你有一个可以分成子任务的任务时,你可以使用一个屏障;每个子任务可以在单独的线程中执行,并且每个线程必须在共同点处相遇以组合它们的结果。

java.util.concurrent包中的CyclicBarrier类提供了屏障同步器的实现。

CyclicBarrier类可以通过调用其reset()方法来重用。

以下代码显示了如何在程序中使用循环障碍。

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;class Worker extends Thread {private CyclicBarrier barrier;private int ID;private static Random random = new Random();public Worker(int ID, CyclicBarrier barrier) {this.ID = ID;this.barrier = barrier;}public void run() {try {int workTime = random.nextInt(30) + 1;System.out.println("Thread #" + ID + " is going to work for " + workTime + "  seconds");Thread.sleep(workTime * 1000);System.out.println("Thread #" + ID + " is waiting at the barrier.");this.barrier.await();System.out.println("Thread #" + ID + " passed the barrier.");} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {System.out.println("Barrier is broken.");}}}
public class Main {public static void main(String[] args) {Runnable barrierAction = () -> System.out.println("We are ready.");CyclicBarrier barrier = new CyclicBarrier(3, barrierAction);for (int i = 1; i <= 3; i++) {Worker t = new Worker(i, barrier);t.start();}}
}

上面的代码生成以下结果。

Phasers

Phaser提供类似于CyclicBarrier和CountDownLatch同步器的功能。它提供以下功能:

Phaser是可重复使用的。

在Phaser上同步的参与方数量可以动态更改。在循环障碍中,当创建障碍时,方的数量是固定的。

移相器具有相关的相位编号,从零开始。当所有注册方都到达移相器时,移相器进入下一个阶段,阶段编号加1。相位编号的最大值为Integer.MAX_VALUE。在其最大值之后,相位编号重新从零开始。

Phaser有终止状态。在终止状态的Phaser上调用的所有同步方法立即返回,而不等待提前。

移相器有三种类型的参与者计数:注册参与者计数,到达参与者计数和未参与方计数。

注册方数量是注册同步的方的数量。到达的当事方数目是已经到达移相器的当前阶段的各方的数目。

未携带者数量是尚未到达移动器的当前阶段的各方的数量。

当最后一方到达时,移相器前进到下一阶段。

或者,当所有注册方都到达移动器时,Phaser可以执行移相器操作。

CyclicBarrier允许您执行屏障操作,这是一个Runnable任务。

我们通过在Phaser类的onAdvance()方法中编写代码来指定移相器操作。

我们需要继承Phaser类,并覆盖onAdvance()方法以提供Phaser动作。

以下代码显示了如何表示通过在Phaser上同步启动的任务

import java.util.Random;
import java.util.concurrent.Phaser;class StartTogetherTask extends Thread {private Phaser phaser;private String taskName;private static Random rand = new Random();public StartTogetherTask(String taskName, Phaser phaser) {this.taskName = taskName;this.phaser = phaser;}@Overridepublic void run() {System.out.println(taskName + ":Initializing...");int sleepTime = rand.nextInt(5) + 1;try {Thread.sleep(sleepTime * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(taskName + ":Initialized...");phaser.arriveAndAwaitAdvance();System.out.println(taskName + ":Started...");}
}public class Main {public static void main(String[] args) {Phaser phaser = new Phaser(1);for (int i = 1; i <= 3; i++) {phaser.register();String taskName = "Task  #" + i;StartTogetherTask task = new StartTogetherTask(taskName, phaser);task.start();}phaser.arriveAndDeregister();}
}

上面的代码生成以下结果。

例子

以下代码显示了如何向Phaser添加Phaser Action。

import java.util.concurrent.Phaser;public class Main {public static void main(String[] args) {Phaser phaser = new Phaser() {protected boolean onAdvance(int phase, int parties) {System.out.println("Inside onAdvance(): phase  = " + phase+ ",  Registered Parties = " + parties);// Do not terminate the phaser by returning falsereturn false;}};// Register the self (the "main" thread) as a party phaser.register();System.out.println("#1: isTerminated():" + phaser.isTerminated());phaser.arriveAndDeregister();// Trigger another phase advancephaser.register();phaser.arriveAndDeregister();System.out.println("#2: isTerminated():" + phaser.isTerminated());phaser.forceTermination();System.out.println("#3: isTerminated():" + phaser.isTerminated());}
}

上面的代码生成以下结果。

例2

以下代码显示如何使用移相器生成一些整数。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Phaser;class AdderTask extends Thread {private Phaser phaser;private String taskName;private List<Integer> list;public AdderTask(String taskName, Phaser phaser, List<Integer> list) {this.taskName = taskName;this.phaser = phaser;this.list = list;}@Overridepublic void run() {do {System.out.println(taskName + "  added  " + 3);list.add(3);phaser.arriveAndAwaitAdvance();} while (!phaser.isTerminated());}
}public class Main {public static void main(String[] args) {final int PHASE_COUNT = 2;Phaser phaser = new Phaser() {public boolean onAdvance(int phase, int parties) {System.out.println("Phase:" + phase + ", Parties:" + parties+ ",  Arrived:" + this.getArrivedParties());boolean terminatePhaser = false;if (phase >= PHASE_COUNT - 1 || parties == 0) {terminatePhaser = true;}return terminatePhaser;}};List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());int ADDER_COUNT = 3;phaser.bulkRegister(ADDER_COUNT + 1);for (int i = 1; i <= ADDER_COUNT; i++) {String taskName = "Task  #" + i;AdderTask task = new AdderTask(taskName, phaser, list);task.start();}while (!phaser.isTerminated()) {phaser.arriveAndAwaitAdvance();}int sum = 0;for (Integer num : list) {sum = sum + num;}System.out.println("Sum = " + sum);}
}

上面的代码生成以下结果。

锁存器

锁存器使一组线程等待,直到它到达其终端状态。

一旦锁存器达到其终端状态,它允许所有线程通过。

与障碍不同,它是一个一次性的对象。它不能被重置和重用。

使用锁存器,其中在一定数量的一次性活动完成之前,多个活动不能进行。

例如,一个服务不应该启动,直到它依赖的所有服务都已启动。

java.util.concurrent包中的CountDownLatch类提供了一个锁存器的实现。

import java.util.concurrent.CountDownLatch;
class LatchHelperService extends Thread {private int ID;private CountDownLatch latch;public LatchHelperService(int ID, CountDownLatch latch) {this.ID = ID;this.latch = latch;}public void run() {try {Thread.sleep(1000);System.out.println("Service #" + ID + "  has  started...");} catch (InterruptedException e) {e.printStackTrace();} finally {this.latch.countDown();}}
}class LatchMainService extends Thread {private CountDownLatch latch;public LatchMainService(CountDownLatch latch) {this.latch = latch;}public void run() {try {System.out.println("waiting for services to start.");latch.await();System.out.println("started.");} catch (InterruptedException e) {e.printStackTrace();}}
}public class Main {public static void main(String[] args) {// Create a countdown latch with 2 as its counterCountDownLatch latch = new CountDownLatch(2);LatchMainService ms = new LatchMainService(latch);ms.start();for (int i = 1; i <= 2; i++) {LatchHelperService lhs = new LatchHelperService(i, latch);lhs.start();}}
}

上面的代码生成以下结果。

交换器

交换器允许两个线程在同步点处等待彼此。

当两个线程到达时,它们交换一个对象并继续他们的活动。

Exchanger类提供了交换器同步器的实现。

以下代码显示将使用交换器与客户交换数据的生产者线程。

import java.util.ArrayList;
import java.util.concurrent.Exchanger;class ExchangerProducer extends Thread {private Exchanger<ArrayList<Integer>> exchanger;private ArrayList<Integer> buffer = new ArrayList<Integer>();public ExchangerProducer(Exchanger<ArrayList<Integer>> exchanger) {this.exchanger = exchanger;}public void run() {while (true) {try {System.out.println("Producer.");Thread.sleep(1000);fillBuffer();System.out.println("Producer has produced and waiting:" + buffer);buffer = exchanger.exchange(buffer);} catch (InterruptedException e) {e.printStackTrace();}}}public void fillBuffer() {for (int i = 0; i <= 3; i++) {buffer.add(i);}}
}class ExchangerConsumer extends Thread {private Exchanger<ArrayList<Integer>> exchanger;private ArrayList<Integer> buffer = new ArrayList<Integer>();public ExchangerConsumer(Exchanger<ArrayList<Integer>> exchanger) {this.exchanger = exchanger;}public void run() {while (true) {try {System.out.println("Consumer.");buffer = exchanger.exchange(buffer);System.out.println("Consumer  has received:" + buffer);Thread.sleep(1000);System.out.println("eating:"+buffer);buffer.clear();} catch (InterruptedException e) {e.printStackTrace();}}}  
}
public class Main {public static void main(String[] args) {Exchanger<ArrayList<Integer>> exchanger = new Exchanger<>();ExchangerProducer producer = new ExchangerProducer(exchanger);ExchangerConsumer consumer = new ExchangerConsumer(exchanger);producer.start();consumer.start();}
}

上面的代码生成以下结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/472648.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Java核心技术 卷I》用户界面AWT事件继承层次

AWT事件继承层次 EventObject类有一个子类AWTEvent&#xff0c;它是所有AWT事件类的父类。 Swing组件会生成更多其他事件对象&#xff0c;都直接拓展自EventObject而不是AWTEvent。 AWT将事件分为底层(low-level)事件和语义事件。 语义事件&#xff1a;表示用户的动作事件&…

Ubuntu从入门到精通(一)系统安装

Ubuntu从入门到精通&#xff08;一&#xff09; 1 Ubuntu镜像选择 下载Ubuntu 20.04系统ISO镜像 安装 Ubuntu 20.04系统,就必须有 Ubuntu 20.04系统软件安装程序可以通过浏览器访问Ubuntu20.04的官方站点&#xff0c; 然后在导舰栏找划 Dowwnloads->Mirrors链接&#xff…

用户自定义IP核——ZYNQ学习笔记6

一、试验任务 通过自定义一个 LED IP 核&#xff0c;通过 PS 端的程序来控制底板上 PL 端 LED1 呈现呼吸 灯的效果&#xff0c;并且 PS 可以通过 AXI 接口来控制呼吸灯的开关和呼吸的频率。 二、创建IP核 三、创建工程&#xff0c;调用IP #include "stdio.h" #includ…

Elasticsearch 8.16.0:革新大数据搜索的新利器

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

python:用 sklearn 构建 K-Means 聚类模型

pip install scikit-learn 或者 直接用 Anaconda3 sklearn 提供了 preprocessing 数据预处理模块、cluster 聚类模型、manifold.TSNE 数据降维模块。 编写 test_sklearn_3.py 如下 # -*- coding: utf-8 -*- """ 使用 sklearn 构建 K-Means 聚类模型 "&…

【大数据学习 | HBASE高级】hive操作hbase

一般在查询hbase的数据的时候我们可以直接使用hbase的命令行或者是api进行查询就行了&#xff0c;但是在日常的计算过程中我们一般都不是为了查询&#xff0c;都是在查询的基础上进行二次计算&#xff0c;所以使用hbase的命令是没有办法进行数据计算的&#xff0c;并且对于hbas…

贴代码框架PasteForm特性介绍之markdown和richtext

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

ServletConfig、ServletContext、HttpServletRequest与HttpServletResponse常见API

目录 一、ServletConfig 二、ServletContext 三、ServletContext其他重要API (一)获取文件路径和上下文 (二)域对象的相关API 四、HttpServletRequest常见API (一)获取请求行/头信息相关 (二)获得请求参数相关 五、HttpServletResponse常见API 一、ServletConfig Se…

MySQL缓存使用率超过80%的解决方法

MySQL缓存使用率超过80%的解决方法 一、识别缓存使用率过高的问题1.1 使用SHOW GLOBAL STATUS命令监控1.2 监控其他相关指标二、分析缓存使用率过高的原因2.1 数据量增长2.2 查询模式变化2.3 配置不当三、解决缓存使用率过高的方法3.1 调整Buffer Pool大小3.1.1 计算合理的Buff…

新手教学系列——善用 VSCode 工作区,让开发更高效

引言 作为一名开发者,你是否曾经在项目中频繁地切换不同文件夹,打开无数个 VSCode 窗口?特别是当你同时参与多个项目或者处理多个模块时,这种情况更是家常便饭。很快,你的任务栏上挤满了 VSCode 的小图标,切换起来手忙脚乱,工作效率直线下降。这时候,你可能会问:“有…

springboot004基于springboot004网页时装购物系统(源码+包运行+LW+技术指导)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

丹摩征文活动 |【前端开发】HTML+CSS+JavaScript前端三剑客的基础知识体系了解

前言 &#x1f31f;&#x1f31f;本期讲解关于HTMLCSSJavaScript的基础知识&#xff0c;小编带领大家简单过一遍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 …

进程信号

目录 信号入门 1. 生活角度的信号 2. 技术应用角度的信号 3. 注意 4. 信号概念 5. 用kill -l命令可以察看系统定义的信号列表 6. 信号处理常见方式概览 产生信号 1. 通过终端按键产生信号 Core Dump 2. 调用系统函数向进程发信号 3. 由软件条件产生信号 4. 硬件异…

【链路层】空口数据包详解(4):数据物理通道协议数据单元(PDU)

目录 一、概述 1.1. 头部&#xff08;Header&#xff09;结构 1.2. MIC字段的情况说明 1.3. 有效载荷&#xff08;Payload&#xff09;格式与LLID字段的关联 二、LL Data PDU 2.1. 定义与用途 2.2. 头部字段设置 2.3. 空PDU&#xff08;Empty PDU &#xff09; 2.4. 数…

使用 Web Search 插件扩展 GitHub Copilot 问答

GitHub Copilot 是一个由 GitHub 和 OpenAI 合作开发的人工智能代码提示工具。它可以根据上下文提示代码&#xff0c;还可以回答各种技术相关的问题。但是 Copilot 本身不能回答非技术类型的问题。为了扩展 Copilot 的功能&#xff0c;微软发布了一个名为 Web Search 的插件&am…

24 年第十届数维杯国际数模竞赛赛题浅析

本次万众瞩目的数维杯国际大学生数学建模赛题已正式出炉&#xff0c;无论是赛题难度还是认可度&#xff0c;该比赛都是数模届的独一档&#xff0c;含金量极高&#xff0c;可以用于综测加分、保研、简历添彩等各方面。考虑到大家解题实属不易&#xff0c;为了帮助大家取得好成绩…

无人机检测车辆——多目标检测

目录 YOLOv3&#xff08;You Only Look Once version 3&#xff09;简介 YOLOv3 的主要特点 YOLOv3 的结构 1. 特征提取网络&#xff08;Backbone&#xff09; 2. 检测头&#xff08;Head&#xff09; 3. 输出层 YOLOv3 损失函数 YOLOv3 的优势 YOLOv3 的应用 YOLOv3…

ThriveX 博客管理系统前后端项目部署教程

前端 前端项目地址&#xff1a;https://github.com/LiuYuYang01/ThriveX-Blog 控制端项目地址&#xff1a;https://github.com/LiuYuYang01/ThriveX-Admin Vercel 首先以 Vercel 进行部署&#xff0c;两种方式部署都是一样的&#xff0c;我们以前端项目进行演示 首先我们先…

python的matplotlib实现数据分析绘图

目录 需求 效果 数据分析绘图示例 代码解释 运行结果 需求 分析一个班级中学生成绩分布&#xff0c;并绘图 效果 数据分析绘图示例 import matplotlib.pyplot as plt import numpy as np# 假设的学生成绩数据 np.random.seed(0) # 设置随机种子以确保结果可复现 score…

计算机网络 (3)计算机网络的性能

一、计算机网络性能指标 速率&#xff1a; 速率是计算机网络中最重要的性能指标之一&#xff0c;它指的是数据的传送速率&#xff0c;也称为数据率&#xff08;Data Rate&#xff09;或比特率&#xff08;Bit Rate&#xff09;。速率的单位是比特/秒&#xff08;bit/s&#xff…