并发工具类

Fork/Join框架

    将一个大任务,进行拆分(fork)成n个小任务(直到不可再分),再将小任务运算结果进行join汇总。

    工作密取:例如任务分成了两个线程执行,当A线程执行完后B线程还未执行完,则A线程会去B线程偷取任务执行,执行完之后再放入B,被窃取任务线程永远从头部拿任务执行,而窃取任务的线程从尾部拿任务执行。

     RecursiveAction,用于没有返回结果的任务

     RecursiveTask,用于有返回值的任务

    fork/join框架应该慎用,因为会造成线程之间的上下文切换,如果任务非常简单,那么不会起到省时作用。

代码演示:

/**
     * 同步方法演示,需要返回值
     */
    static class MyTask extends RecursiveTask<Integer> {

        private final int HOLD = 10; // 任务判断阈值
        private int[] src;  // 实际统计的数组
        private int startIndex; //开始统计的下标
        private int endIndex;

        public MyTask(int[] src, int startIndex, int endIndex) {
            this.src = src;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        @Override
        protected Integer compute() {
            if (endIndex - startIndex < HOLD) {
                int count = 0;
                for (int i = startIndex; i <= endIndex; i++) {
                    count += src[i];
                }
                return count;
            } else {
                // 那么继续拆分
                int mid = (startIndex + endIndex) / 2;
                MyTask left = new MyTask(src, startIndex, mid);
                MyTask right = new MyTask(src, mid + 1, endIndex);
                invokeAll(left, right);
                return left.join() + right.join();
            }
        }
    }
    /**
     * 将大数组拆分为小数组求和
     * @param args
     */
    public static void main(String[] args) {
        int[] src = new int[4000];
        for (int i = 0; i < 4000; i++) {
            src[i] = i;
        }
        ForkJoinPool joinPool = new ForkJoinPool();
        MyTask myTask = new MyTask(src, 0, src.length -1);
        joinPool.invoke(myTask);
    }
    /**
     * 查询某文件夹下的文件
     * 异步方法演示,无返回值
     */
    static class MyTask2 extends RecursiveAction {

        private File path;

        public MyTask2(File path) {
            this.path = path;
        }

        @Override
        protected void compute() {
            List<MyTask2> subTasks = new ArrayList<>();
            File[] files = path.listFiles();
            if (files != null) {
                for (File file: files) {
                    if (file.isDirectory()) {
                        subTasks.add(new MyTask2(file));
                    } else {
                        if (file.getAbsolutePath().endsWith(".txt")) {
                            System.out.println("txt文件:" + file.getAbsolutePath());
                        }
                    }
                }
            }
            if (!subTasks.isEmpty()) {
                // invokeAll 得到提交的每个任务的结果
                for (MyTask2 myTask : invokeAll(subTasks)) {
                    myTask.join();
                }
            }
        }
    }
    public static void main(String[] args) {

        ForkJoinPool joinPool = new ForkJoinPool();
        MyTask2 myTask = new MyTask2(new File("d:/"));
        joinPool.execute(myTask);
        myTask.join();
    }

CountDownLatch

    等待n个线程完成后,再执行主线程

public class CountDownTest {
    // 3 表示需要等待的子线程数量
    static CountDownLatch countDownLatch = new CountDownLatch(2);

    static class OneThread implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        }
    }
    static class TwoThread implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown(); // 计数器减一
        }
    }
    public static void main(String[] args) throws InterruptedException {
        OneThread one = new OneThread();
        TwoThread two = new TwoThread();
        LocalDateTime start = LocalDateTime.now();
        new Thread(one).start();
        new Thread(two).start();
        // 等待子线程
        countDownLatch.await();
        LocalDateTime end = LocalDateTime.now();
        Duration duration = Duration.between(start, end);
        System.out.println(duration.toMillis());
    }
}

CyclicBarrier

    是让一组线程达到某个屏障,一直阻塞,直到所有线程都到达屏障后,屏障开放,线程开始运行。

// parties 屏障开放之前,必须等待的线程数 ; barrierAction 屏障开放之后,要执行的线程
CyclicBarrier(int parties, Runnable barrierAction) 
public static void main(String[] args) throws ExecutionException, InterruptedException {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    });
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    });
    executorService.shutdown();
}

CyclicBarrier和CountDownLatch 区别

  • countdownlatch放行条件>=线程数,CyclicBarrier放行条件=线程数
  • CountDownLatch是不可重置的,所以无法重用;而CyclicBarrier则没有这种限制,可以重用
  • 它两目的就不同

Semaphore

    控制同时访问资源的线程数量,可以用在流量控制

/**
 * @Auther: ZXL
 * @Date: 2019/4/5
 * @Description: 模拟简单的连接池
 */
public class SemaphoreDemo {

    private static final int POOL_SIZE = 10;
    private static LinkedList<MyConnection> pool = new LinkedList<>();
    // useFul可用的连接池 useLess不可用的连接池
    private Semaphore useFul, useLess;

    public SemaphoreDemo() {
        this.useFul = new Semaphore(POOL_SIZE);
        this.useLess = new Semaphore(0);
    }
    static {
        for (int i = 0; i < POOL_SIZE; i++) {
            pool.add(new MyConnection());
        }
    }
    /**
     * 归还链接
     */
    public void returnCon(MyConnection connection) throws InterruptedException {
        if (connection != null) {
            System.out.println("等待连接池的线程" + useFul.getQueueLength()+
                    "可用连接池的数量" + useFul.availablePermits());
            useLess.acquire();
            synchronized (pool) {
                pool.addLast(connection);
            }
            useFul.release();
        }
    }
    /**
     * 取出连接
     */
    public MyConnection takeCon() throws InterruptedException {
        // 如果拿不到就会阻塞在这
        useFul.acquire();
        MyConnection connection;
        synchronized (pool) {
            connection = pool.removeFirst();
        }
        // 已用连接+1
        useLess.release();
        return connection;
    }

    public static void main(String[] args) {
        SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
        for (int i = 0; i < 30; i++) {
            Thread a = new Thread(() -> {
                Random random = new Random();
                try {
                    MyConnection connection = semaphoreDemo.takeCon();
                    Thread.sleep(1000 + random.nextInt(100));
                    semaphoreDemo.returnCon(connection);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            a.start();
        }
    }
}

Callable、Future和FutureTask 

转自享学课堂

Callable接口是有返回值的一种线程启动方式。

Future:

可以用在异步调用服务,例如dubbo的异步调用。

isDone(),结束,正常还是异常结束,或者自己取消,返回true;

isCancelled() 任务完成前被取消,返回true;

cancel(boolean)

  • 任务还没开始,返回false
  • 任务已经启动,cancel(true),中断正在运行的任务,中断成功,返回true,cancel(false),不会去中断已经运行的任务
  • 任务已经结束,返回false
    public class FutureDemo {
    
        static class CallDemo implements Callable<Integer> {
    
            @Override
            public Integer call() throws Exception {
                System.out.println("计算开始");
                int num = 0;
                for (int i = 0; i < 10000; i++) {
                    num++;
                }
                System.out.println("计算结束:" + num);
                return num;
            }
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            CallDemo callDemo = new CallDemo();
            FutureTask<Integer> futureTask = new FutureTask<>(callDemo);
            new Thread(futureTask).start();
            //System.out.println("中断结果:" + futureTask.cancel(true));
            System.out.println("正常获取的结果:" + futureTask.get());
            System.out.println("中断结果:" + futureTask.cancel(true));
        }
    }

     

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值