Java笔记(十八)同步和协作工具类
同步和协作工具类
一、读写锁ReentrantReadWriteLock
ReadWriteLock接口的定义为:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
读操作使用读锁,写操作使用写锁。只有"读-读"操作是可以并行的,"读-写"和"写-写"都不行。
始终只有一个线程能进行写操作,在获取写锁时,只有没有任何线程持有任何锁才可以获取到,
在持有写锁时,其他任何线程都获取不到任何锁。在没有其他线程持有写锁的情况下,多个线程可以获取和持有读锁。
ReentrantReadWriteLock的两个构造方法:
public ReentrantReadWriteLock() {
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
其中fair表示是否公平。
二、信号量Semaphore
信号量类Semaphore类用来限制对资源并发访问的线程数,构造方法:
//permits表示许可数量
public Semaphore(int permits)
//fair表示是否公平
public Semaphore(int permits, boolean fair)
Semaphore方法与锁类似,主要有两类方法,获取许可和释放许可:
//阻塞获取许可
public void acquire() throws InterruptedException
//阻塞获取许可,不响应中断
public void acquireUninterruptibly()
//批量获取多个许可
public void acquire(int permits) throws InterruptedException
public void acquireUninterruptibly(int permits)
//尝试获取
public boolean tryAcquire()
//限定等待时间获取
public boolean tryAcquire(int permits, long timeout,
TimeUnit unit) throws InterruptedException
//释放许可
public void release()
限制并发访问数量不超过100的例子:
public class AccessControlService {
public static class ConcurrentLimitException extends RuntimeException {
}
private static final int MAX_PERMITS = 100;
private Semaphore permits = new Semaphore(MAX_PERMITS, true);
public boolean login(String name, String password) {
//每次acquire都会消耗一个许可
if (!permits.tryAcquire()) {
throw new ConcurrentLimitException();
}
return true;
}
public void logout(String name) {
permits.release();
}
}
Semaphore permits = new Semaphore(1);
permits.acquire();
//程序会阻塞在第二个acquire调用
permits.acquire();
System.out.println("acquired");
信号量也是基于AQS实现的。
三、倒计时门栓CountDownLatch
用于需要线程同步的情景。该类相当于一个门栓,一开始是关闭的,所有希望通过该门的线程都需要等待,
然后开始倒计时,倒计时变为0的时候,门栓打开,所有线程通过,它是一次性的,打开后不能关闭。构造函数:
public CountDownLatch(int count)
与多个线程的协作方法:
//检查计数是否为0如果大于0就等待。await可以被中断,也可以设置最长等待时间
public void await() throws InterruptedException
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
//countDown检查计数,如果已经为0,直接返回,否则减少计数,如果新的计数变为0,
//则唤醒所有线程
public void countDown()
public class RacerWithCountDownLatch {
static class Racer extends Thread {
CountDownLatch latch;
public Racer(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try{
this.latch.await();
System.out.println(getName() + " start run "
+ System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
int num = 10;
CountDownLatch latch = new CountDownLatch(1);
Thread[] threads = new Thread[num];
for (int i = 0; i < num; i++) {
threads[i] = new Racer(latch);
threads[i].start();
}
Thread.sleep(1000);
latch.countDown();
/*Thread-0 start run 1545714108398
Thread-3 start run 1545714108398
Thread-4 start run 1545714108398
Thread-5 start run 1545714108398
Thread-6 start run 1545714108398
Thread-7 start run 1545714108399
Thread-8 start run 1545714108399
Thread-9 start run 1545714108399*/
}
}
四、循环栅栏CyclicBarrier
所有线程在到达栅栏后都需要等待其他线程,等所有线程都到达后再一起通过,
它是循环的,可以用作重复的同步。构造方法:
//parties参与线程个数
public CyclicBarrier(int parties)
//barrierAction表示所有线程到达栅栏后,所有线程执行下一步动作前,
//运行参数中的动作,这个动作由最后一个到达栅栏的线程执行
public CyclicBarrier(int parties, Runnable barrierAction)
主要方法:
//等待其他线程到达栅栏,调用await后表示自己已经到达,如果是最后一个到达的,就执行可选命令,执行完毕后,唤醒所有等待的线程,然后重置内部的同步计数
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException,
BrokenBarrierException, TimeoutException
注意:在CyclicBarrier中,参与的线程是互相影响的,只要有其中的一个线程在调用await时被中断或者超时了,
栅栏就会被破坏。此外,如果栅栏动作抛出了异常,栅栏也会被破坏。被破坏后,所有在调用的await线程就会退出,
抛出BrokenBarrierException。
五、ThreadLocal
1.基本概念和用法
线程本地变量:每个线程都有同一个变量的独特拷贝。ThreadLocal是一个泛型类,
接受一个类型参数T,它只有一个空的构造方法,有两个主要的public方法:
//获取值
public T get()
//设置值
public void set(T value)
public class ThreadLocalBasic {
static ThreadLocal<Integer> local = new ThreadLocal<Integer>();
public static void main(String[] args) throws InterruptedException {
Thread child = new Thread(){
@Override
public void run() {
System.out.println("child thread initial " + local.get()); //null
local.set(200);
System.out.println("child thread final: " + local.get()); //
}
};
local.set(100);
child.start();
child.join();
System.out.println("Main thread final : " + local.get()); //
}
}
从上面的例子可以看出,一个线程本地变量,在每个线程都有自己的独立值。
ThreadLocal的其他方法:
//用于提供初始值
protected T initialValue()
//删除当前线程的对应值,删掉后再次调用get就会获取初始值
public void remove()
应用:是实现线程安全、减少竞争的一种方案。
Java笔记(十八)同步和协作工具类的更多相关文章
- java第十九天,Collections集合工具类的使用
Collections Java中集合都实现了Collection接口,那么针对集合一些特定的功能,有没有一个接口或类能够统一的集成一些集合必要的功能呢?当然能.它就是--Collections集合工 ...
- Java笔记(十八)……包
概述 对类文件进行分类管理. 给类提供多层命名空间. 写在程序文件的第一行. 类名的全称的是 包名.类名. 包也是一种封装形式. 访问权限 引用<The Complete Reference&g ...
- python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置
python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...
- 《java面试十八式》--引子
爪哇城中 “喂,你等等我啊”少女气喘吁吁的喊道 “大小姐,你可快点吧,报名马上就要结束了.” 这是爪哇城一年一度的大选比赛,被选上的人会留下来任职,享有名誉和金钱,所以大家都在积极准备. ...
- java调用kettle的job和transfer工具类
package com.woaiyitiaocai.util; import java.util.Map; import java.util.UUID; import org.apache.log4j ...
- Java Class与反射相关的一些工具类
package com.opslab.util; import org.apache.log4j.Logger; import java.io.File;import java.io.IOExcept ...
- Java语言Lang包下常用的工具类介绍_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都 ...
- Java基础学习笔记十八 异常处理
什么是异常?Java代码在运行时期发生的问题就是异常. 在Java中,把异常信息封装成了一个类.当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置.原因等). 异常的继承体系 在 ...
- Java并发(十六):并发工具类——Exchanger
Exchanger(交换者)是一个用于线程间协作的工具类.Exchanger用于进行线程间的数据交换.它提供一个同步点,在这个同步点两个线程可以交换彼此的数据.这两个线程通过exchange方法交换数 ...
随机推荐
- CF 1051F
题意:给定一张n个点,m条边的无向联通图,其中m-n<=20,共q次询问,每次询问求给定两点u,v间的最短路长度 第一眼看见这题的时候,以为有什么神奇的全图最短路算法,满心欢喜的去翻了题解,发现 ...
- shell 按序删除文件
一.按时间排序 cd /data/wosbak/hrs/pre/ && ls -A -t | awk '{if(NR>15){print $9}}' | xargs rm -rf ...
- javaScript中的querySelector()与querySelectorAll()的区别
之前,在JavaScript获取文档元素一文中,我曾介绍了获取文档元素的几种方法,最后一种方法是通过选择器获取文档元素.它的核心思想便是利用querySelector()或querySelectorA ...
- Chrome开发者控制台操作教程
1清空控制台 在控制台下有个clear console的按钮,点击的时候会清空控制台. 清空控制台 2让Chrome中的页面可编辑 有的时候我们需要临时改变页面上的文字,图案等信息,一种常见的方法是 ...
- linux操作系统中的netstat命令查看端口状态的使用和window操作系统查看端口号
1:linux操作系统 netstat 命令用于显示各种网络相关信息,即网络状态.而我主要使用netstat查看端口号是否启动: 参数详情: 1 -a (all)显示所有选项,默认不显示LISTEN相 ...
- Java集合源码学习(三)LinkedList
前面学习了ArrayList的源码,数组是顺序存储结构,存储区间是连续的,占用内存严重,故空间复杂度很大.但数组的二分查找时间复杂度小,为O(1),数组的特点是寻址容易,插入和删除困难.今天学习另外的 ...
- Note for "Some Remarks on Writing Mathematical Proofs"
John M. Lee is a famous mathematician, who bears the reputation of writing the classical book " ...
- tomcat-会话绑定
会话保存 1) session sticky source_ip 原地址绑定 nginx: ip_hash haproxy: source lvs: ...
- lvs - mask标记
将两个服务绑定在一个集群服务中 如何将两种请求绑定在一个集群中通过一个director来调度, 这里需要iptable工具配合实现.首先在prerouting链上做一个标记,通过标记来调度 起两个服务 ...
- react部署
https://www.cnblogs.com/jackson-zhangjiang/p/10095892.html React项目搭建与部署 React项目搭建与部署 一,介绍与需求 1.1,介 ...