JDK并发包的使用

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();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值