ReentrantLock 可重入锁
可重入锁是synchronized的升级版, 提供了更多的场景, 使用比较方便.
ReentrantLock 有以下特性和方法:
可重入 reentrantLock.lock() .unlock()
可中断 reentrantLock.lockInterruptibly(); 通过这个方法加的锁是可以被中断的.
可限时 reentrantLock.tryLock(5. TimeUtils.SECCEND); 5秒内无法获取锁就返回false. 不会永久等待构成死锁.
公平锁 reentrantLock = new ReentrantLock(true);
可重入
package com.zhe.reentrant;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantTest1 implements Runnable {
public static ReentrantLock reentrantLock = new ReentrantLock();
public static int i = 0;
@Override
public void run() {
for (int j = 1; j <= 10000000; j++) {
reentrantLock.lock();
// reentrantLock.lock();
try{
i++;
}finally {
reentrantLock.unlock();
// reentrantLock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantTest1 reentrantTest1 = new ReentrantTest1();
Thread thread1 = new Thread(reentrantTest1);
Thread thread2 = new Thread(reentrantTest1);
thread1.start();thread2.start();
thread1.join(); thread2.join();
System.out.println(i);
}
}
可中断
package com.zhe..reentrant;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantTest2 implements Runnable {
public static ReentrantLock reentrantLock1 = new ReentrantLock();
public static ReentrantLock reentrantLock2 = new ReentrantLock();
int lock;
public ReentrantTest2(int lock){
this.lock = lock;
}
@Override
public void run() {
try{
if (lock == 1){
reentrantLock1.lockInterruptibly(); //通过这个方法加的锁是可以被中断的.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
reentrantLock2.lockInterruptibly();
}else{
reentrantLock2.lockInterruptibly();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
reentrantLock1.lockInterruptibly();
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (reentrantLock1.isHeldByCurrentThread()){
reentrantLock1.unlock();
}
if (reentrantLock2.isHeldByCurrentThread()){
reentrantLock2.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantTest2 reentrantTest21 = new ReentrantTest2(1);
ReentrantTest2 reentrantTest22 = new ReentrantTest2(2);
Thread thread1 = new Thread(reentrantTest21);
Thread thread2 = new Thread(reentrantTest22);
thread1.start();thread2.start();
Thread.sleep(1000);
//中断一个线程
}
}
可限时
package com.zhe.reentrant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantTime implements Runnable {
public static ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
try {
if (reentrantLock.tryLock(5, TimeUnit.SECONDS)){ //5秒后不能获取到锁就返回false
Thread.sleep(6000);
}else{
System.out.println("等待锁超时, 不能获取到锁..");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (reentrantLock.isHeldByCurrentThread())
reentrantLock.unlock();
}
}
public static void main(String[] args) {
ReentrantTime reentrantTime = new ReentrantTime();
Thread t1 = new Thread(reentrantTime);
Thread t2 = new Thread(reentrantTime);
t1.start();t2.start();
}
}
Condition 线程等待和唤醒
Condition常与ReentrantLock一起使用, 类似于Object.wait() 和Object.notify()
package com.zhe.reentrant;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockCondition implements Runnable {
public static ReentrantLock reentrantLock = new ReentrantLock();
public static Condition condition = reentrantLock.newCondition();
@Override
public void run() {
try{
reentrantLock.lock();
condition.await(); //线程进入等待.
System.out.println("我又重新被唤醒了...");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
reentrantLock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockCondition lock = new ReentrantLockCondition();
Thread t1 = new Thread(lock);
t1.start();
Thread.sleep(2000); //等待2秒后再唤醒
reentrantLock.lock();
condition.signal(); //唤醒t1线程
Thread.sleep(2000); //等待2秒后再释放锁, 所以t1线程虽然被唤醒, 但还是要等2秒主线程释放锁后才能继续执行
reentrantLock.unlock();
}
}
Semaphore 共享锁
可创建多个信号, 允许多个线程获取到信号, 并同时进入临界区
package com.zhe.reentrant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreDemo implements Runnable {
//定义5个许可
final Semaphore semaphore = new Semaphore(5);
@Override
public void run() {
try{
//获取许可, 前5个线程可获得许可
semaphore.acquire();
Thread.sleep(2000);
System.out.println("我拿到了许可, 并已执行完任务了..");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放许可
semaphore.release();
}
}
public static void main(String[] args) {
//创建一个线程池定义20个线程
ExecutorService executorService = Executors.newFixedThreadPool(20);
SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
for (int i = 0; i < 20; i++) {
//创建20个线程
executorService.execute(semaphoreDemo);
}
}
}
ReadWriteLock 读写锁
读写分离锁
在读的时候使用读锁, 可以允许所有线程同时进入读取.
在写的时候使用写锁, 阻塞写, 只允许单个线程写入.
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readWriteLock.readLock(); //获取读锁
readWriteLock.writeLock(); //获取写锁
CountDownLatch 倒数计时器
package com.zhe.reentrant;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo implements Runnable {
//定义倒数计时器, 等待10个线程都执行完毕, 再执行主线程
public static CountDownLatch downLatch = new CountDownLatch(10);
@Override
public void run() {
try {
//模拟检查任务
Thread.sleep(new Random().nextInt(10)*1000);
System.out.println(Thread.currentThread().getId()+"检查完毕...");
downLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
CountDownLatchDemo demo = new CountDownLatchDemo();
for (int i = 0; i < 10; i++) {
executorService.execute(demo);
}
//等待检查
downLatch.await();
//执行主线程
System.out.println("开火...");
//关闭所有线程
executorService.shutdown();
}
}
CyclicBarrier 循环栅栏
Cyclic意为循环,也就是说这个计数器可以反复使用。比如,假设我们将计数器设置为10。那么凑齐第一批1
0个线程后,计数器就会归零,然后接着凑齐下一批10个线程.
线程类
package com.zhe.reentrant;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo implements Runnable{
private final CyclicBarrier cyclicBarrier;
private String soldierName;
public CyclicBarrierDemo(CyclicBarrier cyclicBarrier, String soldierName){
this.cyclicBarrier = cyclicBarrier;
this.soldierName = soldierName;
}
@Override
public void run() {
try {
//第一个await(), 等待所有线程集合
cyclicBarrier.await();
doWork();
//第二个await(), 等待所有线程完成任务
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public void doWork(){
try {
Thread.sleep(new Random().nextInt(10)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(soldierName + "任务完成...");
}
}
主线程类
package com.zhe.reentrant;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierMain {
public static void main(String[] args) {
//定义士兵数量
final int N = 10;
//定义一个线程数组
Thread[] threads = new Thread[N];
boolean flag = false;
//创建循环栅栏, 每当全部线程到达后会执行BarrierRun中的run方法
CyclicBarrier cyclicBarrier = new CyclicBarrier(N,new BarrierRun(flag, N));
//开启10个线程
for (int i = 0; i < 10; i++) {
System.out.println("士兵"+i+"报道...");
threads[i] = new Thread(new CyclicBarrierDemo(cyclicBarrier, "士兵"+i));
threads[i].start();
}
}
}
栅栏触发后的Runnable类
package com.zhe.reentrant;
public class BarrierRun implements Runnable {
private boolean flag;
private int N;
public BarrierRun(boolean flag, int n) {
this.flag = flag;
this.N = n;
}
@Override
public void run() {
if (flag){
System.out.println("司令: 士兵"+N+"个全部执行任务完毕..");
}else {
System.out.println("司令: 士兵"+N+"个全部集合完毕..");
flag = true;
}
}
}
LockSupport 线程挂起
park() : 线程挂起
unpark(): 线程恢复
park()和unpark()执行的先后顺序并不会引起线程冻结.
并且在中断后不会抛出中断异常, 但是会响应中断, 可以通过Thread.interrupted()方法得到是否被中断.
并发容器
集合的包装
//普通的HashMap是线程不安全的, 通过这个包装类会变成线程安全的.
Map map = Collections.synchronizedMap(new HashMap());
List list = Collections.synchronizedList(new ArrayList());
高性能的HashMap
ConcurrentHashMap map = new ConcurrentHashMap();
BlockingQueue 阻塞队列
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(1000);
高性能的队列
ConcurrentLinkedQueue linkedQueue = new ConcurrentLinkedQueue();
回调接口
beforeExecute: 线程执行之前
afterExecute: 线程执行之后
terminated: 线程池退出
package com.zhe.reentrant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo {
public static class MyTask implements Runnable{
private String name;
public MyTask(String name){
this.name = name;
}
@Override
public void run() {
System.out.println("正在执行Thread ID:"+Thread.currentThread().getId()+", Task name="+name);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//5: 核心线程数
//5: 最大线程数
//0L: 最大线程数与核心线程数之间的线程的生存时长
//unit: 时间单位
//BlockingDeque: 阻塞队列
ExecutorService executorService = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()){
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("准备执行, task name:" + ((MyTask)r).name);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("执行完成, task name:" + ((MyTask)r).name);
}
@Override
protected void terminated() {
System.out.println("线程池关闭...");
}
};
for (int i = 0; i < 5; i++) {
executorService.execute(new MyTask("TaskName-"+i));
}
executorService.shutdown();
}
}
ForkJoinPool 线程池
RecursiveAction
package com.zhe.reentrant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
public class ForkJoinPoolAction {
public static void main(String[] args) throws InterruptedException {
PrintTask task = new PrintTask(0, 300);
//创建实例,并执行分割任务
ForkJoinPool pool = new ForkJoinPool();
pool.submit(task);
//线程阻塞,等待所有任务完成
pool.awaitTermination(2, TimeUnit.SECONDS);
pool.shutdown();
}
}
package com.zhe.reentrant;
import java.util.concurrent.RecursiveAction;
public class PrintTask extends RecursiveAction{
private static final int THRESHOLD = 50; //最多只能打印50个数
private int start;
private int end;
public PrintTask(int start, int end) {
super();
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if(end - start < THRESHOLD){
for(int i=start; i<end; i++){
System.out.println(Thread.currentThread().getName()+"的i值:"+i);
}
}else {
int middle =(start+end)/2;
PrintTask left = new PrintTask(start, middle);
PrintTask right = new PrintTask(middle, end);
//并行执行两个“小任务”
left.fork();
right.fork();
}
}
}
RecursiveTask
package com.zhe.reentrant;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.Future;
public class ForkJoinPoolTask {
public static void main(String[] args) throws ExecutionException, InterruptedException {
int[] arr = new int[100];
Random rd = new Random();
int total = 0;
for (int i = 0; i < 100; i++) {
int temp = rd.nextInt(20);
arr[i] = temp;
total += temp;
}
System.out.println("初始化数组的总数:"+total);
SumTask task = new SumTask(arr, 0, arr.length);
//创建一个ForkJoinPool线程池
ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
//将任务提交给线程池
ForkJoinTask<Integer> resultTask = forkJoinPool.submit(task);
//获取线程池返回的结果
Integer integer = resultTask.get();
System.out.println(integer);
//关闭线程池
forkJoinPool.shutdown();
}
}
package com.zhe.reentrant;
import java.util.concurrent.RecursiveTask;
public class SumTask extends RecursiveTask<Integer> {
private static final int THRESHOLD = 20;
private int[] arr;
private int start;
private int end;
public SumTask(int[] arr, int i, int length) {
super();
this.arr = arr;
this.start = i;
this.end = length;
}
@Override
protected Integer compute() {
int sum = 0;
if(end - start < THRESHOLD){
for (int i = start; i < end; i++) {
sum += arr[i];
}
return sum;
}else{
int middle = (end + start)/2;
SumTask leftTask = new SumTask(arr, start, middle);
SumTask rightTask = new SumTask(arr, middle, end);
leftTask.fork();
rightTask.fork();
return leftTask.join()+rightTask.join();
}
}
}