JDK并发包一
JDK并发包一
同步控制是并发程序必不可少的重要手段,synchronized是一种最简单的控制方法。但JDK提供了更加强大的方法————重入锁
重入锁
重入锁使用java.util.concurrent.locks.ReentrantLock类来实现。
ReentrantLock有几个重要的方法
- lock()获得锁,如果锁已占用,则等待。
- lockInterruptibly()获得锁,优先响应中断。
- tryLock() 尝试获得锁若成功返回true 失败返回false 不等待立即返回
- tryLock(long time,TimeUnit unit) 在给定的时间内进行等待
- unlock()释放锁
public class MyTest {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new ReenterLock());
Thread thread2 = new Thread(new ReenterLock());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(i);
}
public static class ReenterLock implements Runnable {
@Override
public void run() {
for (int j = 0; j < 1000000; j++) {
lock.lock();
try {
i++;
} finally {
lock.unlock();
}
}
}
}
}
与synchronized相比重入锁更加灵活 一个线程可以多次获取锁,获取多少次一定要释放多少次
中断响应
对于synchronized相比如果一个线程等待锁,只有两种情况,要么获得锁继续执行,要么等待。重入锁可以有另一种情况————中断thread2.interrupt()
/**
* 中断响应
*/
public static class IntLock implements Runnable {
int lock;
public static ReentrantLock lock1=new ReentrantLock();
public static ReentrantLock lock2=new ReentrantLock();
public IntLock(int lock) {
this.lock = lock;
}
@Override
public void run() {
try {
if (lock==1){
lock1.lockInterruptibly();
Thread.sleep(500);
lock2.lockInterruptibly();
}else {
lock2.lockInterruptibly();
Thread.sleep(500);
lock1.lockInterruptibly();
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (lock1.isHeldByCurrentThread())
lock1.unlock();
if (lock2.isHeldByCurrentThread())
lock2.unlock();
System.out.println(Thread.currentThread().getName()+":线程退出");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new IntLock(1));
Thread thread2 = new Thread(new IntLock(2));
thread1.start();
thread2.start();
Thread.sleep(2000);
thread2.interrupt();
}
thread2获得了thread1的锁thread1获得了thread2的锁两个线程相互等待。 程序形成死锁thread2.interrupt()执行后thread2中断 自动释放获得的所有锁,thread1可以继续执行。真正完成的只有thread1
锁申请等待限时
除了上面中断通过外部通知的方式避免死锁还有另一种方法,限时等待tryLock()
tryLock()方法有两个参数一个表示等待时长,一个是计时单位,在设置的时间内线程会请求获取锁,超过设置的时间还没获得锁就会返回false。获得成功就返回true
公平锁
在大多数情况下锁都是非公平的,即线程不是按照请求在锁不可用时锁的先后顺序获得锁的,系统只会从等待的线程中随机选一个,而公平锁会按照请求顺序在锁可用是分配锁。ReentrantLock lock1=new ReentrantLock(true);创建锁时在构造方法传入true时此锁就是公平锁,公平锁需要一个有序队列来实现因此成本较高性能低下没特殊要求一般不用。
Condition条件
使用synchronized进行通知就使用Object.wait() ,Object.notify() ,使用锁时Condition的方法几乎相同。
- await()方法会使当前线程等待,同时释放当前锁,当其他线程中使用signal()或者signalAll()方法时线程会重现获得锁继续执行,当线程中断时也能跳出等待
- awaitUninterruptibly()方法与await()基本相同,但是它并不会在等待过程中响应中断
- singnal()方法用于唤醒一个等待中的线程,signalAll()唤醒所有线程
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
public static void main(String[] args) {
Thread thread = new Thread(new ReenterLockCondition());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
condition.signal();
lock.unlock();
}
public static class ReenterLockCondition implements Runnable {
@Override
public void run() {
try {
lock.lock();
condition.await();
System.out.println("线程开始执行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
在执行Conidition.await()之前要求当前线程必须持有相关的重入锁,执行signal()也一样也需要先持有重入锁,在singnal()执行后一般需要释放相关重入锁,否则唤醒的线程无法重新获得相关重入锁无法继续执行。
读写锁
读写锁是分离读操作与写(修改,删除,添加)的锁,可以更大程度提高性能。
读 | 写 | |
---|---|---|
读 | 非阻塞 | 阻塞 |
写 | 阻塞 | 阻塞 |
如果一个系统中有大量的读操作,那么读写锁就能发挥更大功效。
public static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();//读写锁
public static Lock read = readWriteLock.readLock();//读锁
public static Lock write=readWriteLock.writeLock();//写锁
倒计时器
对于某个线程需要等待其他几个线程执行完毕自己再执行比较适用
假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。
public static final CountDownLatch end = new CountDownLatch(10);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(new CountDownLatchDemo());
}
try {
end.await();
System.out.println("准备完毕");
executorService.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class CountDownLatchDemo implements Runnable {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10)*1000);
System.out.println(Thread.currentThread().getName()+"准备完毕");
end.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
循环栅栏
CyclicBarrier实现的功能与CountDownLatch类似但刚强大,CyclicBarrier可以实现计数器的复用,
public class Soldier implements Runnable{
private String soldier;
private CyclicBarrier cyclicBarrier;
public Soldier(String soldier, CyclicBarrier cyclicBarrier) {
this.soldier = soldier;
this.cyclicBarrier = cyclicBarrier;
}
public void doWork(){
try {
Thread.sleep(Math.abs(new Random().nextInt()%10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.soldier+"任务完成");
}
@Override
public void run() {
try {
this.cyclicBarrier.await();
doWork();
this.cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public class BarrierRun implements Runnable {
private boolean flag;
private int i;
public BarrierRun(boolean flag, int i) {
this.flag = flag;
this.i = i;
}
@Override
public void run() {
if (this.flag) {
System.out.println("任务完成");
}else {
System.out.println("集合完毕");
}
}
}
public static void main(String[] args) {
Thread[] threads=new Thread[10];
CyclicBarrier cyclicBarrier = new CyclicBarrier(10, new BarrierRun(false, 10));
System.out.println("队伍集合");
for (int i = 0; i < 10; i++) {
System.out.println("士兵"+i+"报道");
threads[i]=new Thread(new Soldier("士兵"+i,cyclicBarrier));
threads[i].start();
}
}
JDK并发包一的更多相关文章
- Java 并发编程实践基础 读书笔记: 第三章 使用 JDK 并发包构建程序
一,JDK并发包实际上就是指java.util.concurrent包里面的那些类和接口等 主要分为以下几类: 1,原子量:2,并发集合:3,同步器:4,可重入锁:5,线程池 二,原子量 原子变量主要 ...
- Java并发程序设计(四)JDK并发包之同步控制
JDK并发包之同步控制 一.重入锁 重入锁使用java.util.concurrent.locks.ReentrantLock来实现.示例代码如下: public class TryReentrant ...
- Java多线程--JDK并发包(2)
Java多线程--JDK并发包(2) 线程池 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. JDK有一套Executor框架,大概包括Executor.Ex ...
- Java多线程--JDK并发包(1)
Java多线程--JDK并发包(1) 之前介绍了synchronized关键字,它决定了额一个线程是否可以进入临界区:还有Object类的wait()和notify()方法,起到线程等待和唤醒作用.s ...
- 3 JDK并发包
JDK内部提供了大量实用的API和框架.本章主要介绍这些JDK内部功能,主要分为3大部分: 首先,介绍有关同步控制的工具,之前介绍的synchronized就是一种同步控制手段,将介绍更加丰富的多线程 ...
- 第3章 JDK并发包(三)
3.2 线程复用:线程池 一种最为简单的线程创建和回收的方法类似如下代码: new Thread(new Runnable() { @Override public void run() { // d ...
- JDK并发包二
JDK并发包二 线程复用--线程池 在线程池中,总有那么几个活跃的线程,当程序需要线程时可以从池子中随便拿一个控线程,当程序执行完毕,线程不关闭,而是将这个线程退会到池子,等待使用. JDK提供了一套 ...
- 第3章 JDK并发包(五)
3.3 不要重复发明轮子:JDK的并发容器 3.3.1 超好用的工具类:并发集合简介 JDK提供的这些容器大部分在java.util.concurrent包中. ConcurrentHashMap:这 ...
- java多线程:jdk并发包的总结(转载)
转载地址:http://blog.csdn.net/yangbutao/article/details/8479520 1.java 高并发包所采用的几个机制(CAS,volatile,抽象队列同步) ...
随机推荐
- .NET Design Patterns
设计模式分组 GoF设计模式著作中的23种设计模式分为3组:创建型(Creational).结构型(Structural)和行为型(Behavional). 创建型 创建型处理对象构造和引用.它们将对 ...
- windows调起git bash执行sh脚本定时统计git仓库代码量
本来挺简单的一个东西硬是弄了两天 心力交瘁 找了网上不少资料 整理一下发给大家 首先是统计每个人的代码量的git命令 在网上找的 我这里做了以下修改 git log --format='%aN'|so ...
- JAVA 面试相关
1. int和Integer有什么区别? 答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十三)——istio+dapr构建多运行时服务网格之生产环境部署
之前所有的演示都是在docker for windows上进行部署的,没有真正模拟生产环境,今天我们模拟真实环境在公有云上用linux操作如何实现istio+dapr+电商demo的部署. 目录:一. ...
- [bug] HDFS:DataXceiver error processing WRITE_BLOCK operation
文件格式有误,导致读取错误,我的是把制表符敲成了空格
- [DB] CDH集群规划
配置 三台机器:node01.node02.node03 node01:6G+60G node02:2G+40G node03:2G+40G 组件 Cloudera Managerment Servi ...
- Select Screen 0 with xrandr Ask QuestionScreen 0" here describes your whole virtual display made of these two outputs: eDP-1-
Screen 0" here describes your whole virtual display made of these two outputs: eDP-1-1: physica ...
- 10.13 nc:多功能网络工具
nc命令 是一个简单.可靠.强大的网络工具,它可以建立TCP连接,发送UDP数据包,监听任意的TCP和UDP端口,进行端口扫描,处理IPv4和IPv6数据包. 如果系统没有nc命令,那么可以手 ...
- Nginx|Apache目录权限禁止执行PHP设置
Ngnix: location ~ /upload/.*.(php|php5)?$ { deny all; } 这就是禁止upload内执行php,但是图片可以打开哦 多目录禁止: location ...
- 为何使用thrift-rpc与http的选择
在工作中偶然看到公司旧架构在loaclserver中使用的是thrift,遂记录一下 thrif作为一种rpc框架 接口描述语言和二进制通信协议,至于为何使用thrift 其问题本质是为何在已有htt ...