Java线程的并发工具类

1、Fork-Join

Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可拆发),再将一个个的小任务运算的结果进行join汇总。MapReduce就是这种思想。

Fork/Join的标准使用范式:

实现案例:

public class MakeArray {
    public static final int ARRAY_LENGTH = 1000000;
    public static int[] makeArray() {
        Random random = new Random();
        int[] ints = new int[ARRAY_LENGTH];
        for (int i = 0; i < ARRAY_LENGTH; i++) {
            ints[i] = random.nextInt(ARRAY_LENGTH * 3);
        }
        return ints;
    }
}

public class SumArray {
    private static class SumTask extends RecursiveTask<Integer> { //继承抽象类
        private final static int THRESHOLD = MakeArray.ARRAY_LENGTH/10;
        private int[] src; //表示要实际统计的数组
        private int fromIndex;//开始统计的下标
        private int toIndex;//统计到哪里结束的下标
        public SumTask(int[] src, int fromIndex, int toIndex) {
            this.src = src;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }
        @Override
        protected Integer compute() {
            if (toIndex - fromIndex < THRESHOLD) {
                int count = 0;
                for (int i = fromIndex; i < toIndex; i++) {
                    count = count + src[i];
                }
                return count;
            } else {
                int mid = (fromIndex + toIndex) >> 1;
                SumTask left = new SumTask(src, fromIndex, mid); //拆分
                SumTask right = new SumTask(src, mid, toIndex);
                invokeAll(left, right);
                return left.join() + right.join();
            }
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        int[] src = MakeArray.makeArray();
        long start = System.currentTimeMillis();
        SumTask sumTask = new SumTask(src, 0, src.length);
        pool.invoke(sumTask); //同步调用
        System.out.println("Task is running...");
        System.out.println("The count is " + sumTask.join() + ", spend time: " +
                (System.currentTimeMillis() - start) + "ms");
    }
}

2、CountDownLatch

作用:是一组线程等待其他的线程完成工作以后在执行,加强版join

await()用来等待,countDown()负责计数器减一

/**
 * 类说明:演示CountDownLatch,有5个初始化线程,6个扣除点
 * 扣除完毕后,主线程和业务线程才能继续自己的工作
 */
public class UseCountDownLatch {
    static CountDownLatch latch = new CountDownLatch(6);

    //初始化线程(只有一步, 有4个线程)
    private static class InitThread implements Runnable {
        @Override
        public void run() {
            System.out.println("Thread_" + Thread.currentThread().getId() + " ready init work...");
            latch.countDown();//初始化线程完成工作了,countDown方法只扣减一次
            for (int i = 0; i < 2; i++) {
                System.out.println("Thread_" + Thread.currentThread().getId() + ".....continue to do it's work");
            }
        }
    }
    //业务线程
    private static class BusyThread implements Runnable {
        @Override
        public void run() {
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("BusyThread_" + Thread.currentThread().getId() + " do business----");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //单独的初始化线程,初始化分为2步,需要扣减2次
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1);
                    System.out.println("Thread_" + Thread.currentThread().getId() + " ready init work step 1st....");
                    latch.countDown();//每完成一步初始化工作,扣减一次
                    System.out.println("begin step 2nd...");
                    Thread.sleep(1);
                    System.out.println("Thread_"+Thread.currentThread().getId()
                            +" ready init work step 2nd......");
                    latch.countDown();//每完成一步初始化工作,扣减一次
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new BusyThread()).start();
        for (int i = 0; i <= 3; i++) {
            Thread thread = new Thread(new InitThread());
            thread.start();
        }
        latch.await();
        System.out.println("Main do it's work...");
    }
}

输出结果:

Thread_10 ready init work step 1st....
begin step 2nd...
Thread_10 ready init work step 2nd......
Thread_12 ready init work...
Thread_12.....continue to do it's work
Thread_12.....continue to do it's work
Thread_13 ready init work...
Thread_13.....continue to do it's work
Thread_13.....continue to do it's work
Thread_14 ready init work...
Thread_14.....continue to do it's work
Thread_14.....continue to do it's work
Thread_15 ready init work...
Thread_15.....continue to do it's work
Thread_15.....continue to do it's work
BusyThread_11 do business----
Main do it's work...

3、CyclicBarrier

作用:让一组线程达到某个屏障被阻塞,一直到组内最后一个线程达到屏障时,屏障开放,所有被阻塞的线程会继续运行CyclicBarrier(int parties)

CyclicBarrier(int parties, Runnable barrierAction),屏障开放,barrierAction定义的任务会执行

public class UseCyclicBarrier {
    private static CyclicBarrier barrier = new CyclicBarrier(5,new CollectThread());
    private static ConcurrentHashMap<String,Long> resultMap
            = new ConcurrentHashMap<>();//存放子线程工作结果的容器

    //负责屏障开放以后的工作
    private static class CollectThread implements Runnable {
        @Override
        public void run() {
            StringBuilder builder = new StringBuilder();
            for (Map.Entry<String, Long> entry : resultMap.entrySet()) {
                builder.append("[" + entry.getValue() + "]");
            }
            System.out.println("result = " + builder);
            System.out.println("do other business...");
        }
    }
    //工作线程
    private static class SubThread implements Runnable {
        @Override
        public void run() {
            long id = Thread.currentThread().getId();//
            resultMap.put(Thread.currentThread().getId() + "", id);
            Random random = new Random();//随机决定工作线程是否睡眠
            try {
                if (random.nextBoolean()) {
                    Thread.sleep(2000 + id);
                    System.out.println("Thread_" + id + "...do something");
                }
                System.out.println(id + "...is await");
                barrier.await();
                Thread.sleep(2000 + id);
                System.out.println("Thread_" + id + "...do it's business");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        for(int i=0;i<=4;i++){
            Thread thread = new Thread(new SubThread());
            thread.start();
        }
    }
}

输出结果:

10...is await
11...is await
12...is await
Thread_14...do something
14...is await
Thread_13...do something
13...is await
result = [11][12][13][14][10]
do other business...
Thread_11...do it's business
Thread_10...do it's business
Thread_12...do it's business
Thread_13...do it's business
Thread_14...do it's business

4、CountDownLatch与CyclicBarrier的区别

  • CountDownLatch放行由第三者控制,CyclicBarrier放行由一组线程本身控制
  • CountDownLatch放行条件 >= 线程数,CyclicBarrier放行条件 = 线程数

5、Semaphore

控制同时访问某个特定资源的线程数量,一般用在流量控制

public class DBPoolSemaphore {
    private final static int POOL_SIZE = 10;
    private final Semaphore useful, useless;//useful表示可用的数据库连接,useless表示已用的数据库连接
    public DBPoolSemaphore() {
        this.useful = new Semaphore(POOL_SIZE);
        this.useless = new Semaphore(0);
    }
    //存放数据库连接的容器
    private static LinkedList<Connection> pool = new LinkedList<>();
    //初始化池
    static {
        for (int i = 0; i < POOL_SIZE; i++) {
            pool.addLast(SqlConnectImpl.fetchConnection());
        }
    }
    //归还连接
    public void returnConnection(Connection connection) throws InterruptedException {
        if (connection != null) {
            System.out.println("当前有" + useful.getQueueLength() + "个线程等待数据库连接!!" +
            "可用连接数:" + useful.availablePermits());
            useless.acquire();
            synchronized (pool) {
                pool.addLast(connection);
            }
            useful.release();
        }
    }
    //从连接池中获取连接
    public Connection getConnection() throws InterruptedException {
        useful.acquire();
        Connection conn;
        synchronized (pool) {
            conn = pool.removeFirst();
        }
        useless.release();
        return conn;
    }

    private static class SqlConnectImpl implements Connection {

        public static final Connection fetchConnection(){
            return new SqlConnectImpl();
        }
        //省略其它代码
    }
}

public class SemaphoreClient {
    private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
    //业务线程
    private static class BusyThread extends Thread {
        @Override
        public void run() {
            Random random = new Random();//让每一个线程持有连接的时间不一样
            long start = System.currentTimeMillis();
            try {
                Connection connection = dbPool.getConnection();
                System.out.println("Thread_" + Thread.currentThread().getId() + "_获取数据库连接共耗时【" +
                        (System.currentTimeMillis() - start) + "】ms");
                Thread.sleep(100 + random.nextInt(100));//模拟业务线程,线程持有连接使用时间
                System.out.println("查询数据完成,归还连接!");
                dbPool.returnConnection(connection);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            new BusyThread().start();
        }
    }
}

6、Exchange

两个线程之间的数据交换,实际应用中会比较少用

7、Callable、Future和FutureTask

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

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

cancel(boolean):

  1. 任务还没开始,返回true
  2. 任务已经开启,cancel(true),中断正在运行的任务,中断成功,返回true;cancel(false)不会去中断正在运行中的任务
  3. 任务已经结束,返回false
public class FutureClient {
    //实现Callable接口,允许有返回值
    private static class UseCallable implements Callable<Integer> {
        private int sum;
        @Override
        public Integer call() throws Exception {
            System.out.println("Callable子线程开始计算");
            Thread.sleep(2000);
            for (int i = 0; i < 5000; i++) {
                sum = sum + i;
            }
            System.out.println("Callable子线程计算完成,结果 = " + sum);
            return sum;
        }
    }

    public static void main(String[] args) throws Exception {
        UseCallable call = new UseCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(call);
        new Thread(futureTask).start();
        Random random = new Random();
        Thread.sleep(1);
        if (random.nextBoolean()) {
            System.out.println("Get UseCallable result = " + futureTask.get());
        } else {
            System.out.println("中断计算");
            futureTask.cancel(true);
        }
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值