Java并发编程——工具类

话不多说,直接撸代码。

一、CountDownLatch使用示例

package com.alex.latch;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author: alex
 * @Date: 2019/3/20
 * @Description: 演示CountDownLatch的使用方法。
 * 龟兔赛跑的例子,兔子先到达终点,但是比赛继续,需要等待乌龟也到达终点后,比赛结束。
 */
public class RunningRace {

    private static final CountDownLatch latch = new CountDownLatch(2);
    private static final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

    /**
     * 兔子的线程类
     */
    static class RabbitThread implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println("兔子线程" + Thread.currentThread().getName() + "开始起跑");
                Thread.sleep(1000);  //兔子跑的快,所以只用1s就可以到达终点
                System.out.println("兔子线程" + Thread.currentThread().getName() + "跑到终点");
                latch.countDown();  //兔子到达终点,计数减一
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 乌龟线程
     */
    static class TurtleThread implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println("乌龟线程" + Thread.currentThread().getName() + "开始起跑");
                Thread.sleep(3000); //乌龟跑的慢,所以用3s才可以到达终点
                System.out.println("乌龟线程" + Thread.currentThread().getName() + "跑到终点");
                latch.countDown();  //乌龟到达终点,计数减一
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        try {
            System.out.println("龟兔赛跑比赛开始...");
            fixedThreadPool.submit(new RabbitThread()); //兔子起跑
            fixedThreadPool.submit(new TurtleThread()); //乌龟起跑
            /**
             * 1、要保证兔子和乌龟都到达终点后,才可以完成比赛。
             * 2、要主要使用await方法,而不是wait方法。wait方法是等待线程,在此处是不起作用的。
             * 3、await方法是CountDownLatch的阻塞方法。当前线程等到锁存器计数到零,继续执行程序。
             */
            latch.await();
            System.out.println("龟兔赛跑比赛结束....");
            fixedThreadPool.shutdownNow();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

龟兔赛跑比赛开始...
兔子线程pool-1-thread-1开始起跑
乌龟线程pool-1-thread-2开始起跑
兔子线程pool-1-thread-1跑到终点
乌龟线程pool-1-thread-2跑到终点
龟兔赛跑比赛结束....

2、CyclicBarrier使用示例

package com.alex.cyclicbarrier;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author: alex
 * @Date: 2019/3/20
 * @Description: 演示CyclicBarrier用法。利用考试的例子来说明CyclicBarrier的用法。
 * 场景描述:
 * 模拟有5个学生进行考试,当五个学生都交卷之后,老师开始批卷。
 */
public class ExamDemo {
    private static final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

    public static void main(String[] args) {
        try {
            /**
             * CyclicBarrier有两个构造方法
             * public CyclicBarrier(int parties, Runnable barrierAction) {} 当parties个线程执行完成后,随机获取一个线程去执行barrierAction动作
             * public CyclicBarrier(int parties) {}当parties个线程执行完成后,才可以进行后续操作。(与CountDownLatch类似)
             */
            CyclicBarrier barrier  = new CyclicBarrier(5,new Thread(new TeacherThread()));
            fixedThreadPool.submit(new StudentThread(1000,barrier));
            fixedThreadPool.submit(new StudentThread(2000,barrier));
            fixedThreadPool.submit(new StudentThread(3000,barrier));
            fixedThreadPool.submit(new StudentThread(4000,barrier));
            fixedThreadPool.submit(new StudentThread(5000,barrier));
            fixedThreadPool.shutdown();
//            for(int i=0;i<5;i++) {
//               new Thread(new StudentThread(1000*(i+1),barrier)).start();
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 学生线程,负责答题交卷
     */
    static class StudentThread implements Runnable {
        private CyclicBarrier cyclicBarrier;
        private long answerTime = 1000;

        public StudentThread(long answerTime,CyclicBarrier cyclicBarrier) {
            this.answerTime = answerTime;
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                System.out.println("学生线程" + Thread.currentThread().getName() + "开始答题...");
                Thread.sleep(answerTime);  //答题时间
                System.out.println("学生线程" + Thread.currentThread().getName() + "结束答题...交卷");
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 老师线程,负责批卷
     */
    static class TeacherThread implements Runnable {
        @Override
        public void run() {
            System.out.println("老师线程" + Thread.currentThread().getName() + "开始批卷...");
        }
    }
}


运行结果:

学生线程pool-1-thread-1开始答题...
学生线程pool-1-thread-2开始答题...
学生线程pool-1-thread-3开始答题...
学生线程pool-1-thread-5开始答题...
学生线程pool-1-thread-4开始答题...
学生线程pool-1-thread-1结束答题...交卷
学生线程pool-1-thread-2结束答题...交卷
学生线程pool-1-thread-3结束答题...交卷
学生线程pool-1-thread-4结束答题...交卷
学生线程pool-1-thread-5结束答题...交卷
老师线程pool-1-thread-5开始批卷...

3、Semaphore使用示例

package com.alex.semaphore;

import java.util.LinkedList;
import java.util.concurrent.Semaphore;

/**
 * @author: alex
 * @Date: 2019/3/20
 * @Description: 演示Semaphore的使用方法,用来控制同时访问特定资源的线程数量。
 * 通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可。
 */
public class DBConnectionPool {

    //使用LinkedList存放连接实体,先入先出,取连接从头获取,归还连接放入到队尾
    private LinkedList<DBConnection> connPoolList = null;
    //信号量
    private Semaphore semaphore = null;

    /**
     * 构造方法
     * @param size 连接池的大小
     */
    public DBConnectionPool(int size) {
        //初始化连接池
        connPoolList = new LinkedList<>();
        for (int i = 0; i < size; i++) {
            connPoolList.push(new DBConnection("conn_" + i)); //生成连接放入到池中
        }
        //初始化信号量
        semaphore = new Semaphore(size);
    }

    /**
     * 获取连接
     *
     * @return 连接实体
     */
    public DBConnection getConnection() {
        try {
            semaphore.acquire(); //获取一个许可,信号量减一
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DBConnection conn = null;
        synchronized (connPoolList) {
            //同步获取一个连接
            conn = connPoolList.removeFirst(); //从集合中删除并返回第一个元素
        }
        return conn;
    }

    /**
     * 释放连接
     *
     * @param conn 连接
     */
    public void releaseConnection(DBConnection conn) {
        synchronized (connPoolList) {
            connPoolList.addLast(conn); //将指定的元素追加到此集合的末尾。
        }
        semaphore.release();  //释放许可,信号量加一
    }
}


DBConnection实体
package com.alex.semaphore;

import java.util.LinkedList;
import java.util.concurrent.Semaphore;

/**
 * @author: alex
 * @Date: 2019/3/20
 * @Description: 演示Semaphore的使用方法,用来控制同时访问特定资源的线程数量。
 * 通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可。
 */
public class DBConnectionPool {

    //使用LinkedList存放连接实体,先入先出,取连接从头获取,归还连接放入到队尾
    private LinkedList<DBConnection> connPoolList = null;
    //信号量
    private Semaphore semaphore = null;

    /**
     * 构造方法
     * @param size 连接池的大小
     */
    public DBConnectionPool(int size) {
        //初始化连接池
        connPoolList = new LinkedList<>();
        for (int i = 0; i < size; i++) {
            connPoolList.push(new DBConnection("conn_" + i)); //生成连接放入到池中
        }
        //初始化信号量
        semaphore = new Semaphore(size);
    }

    /**
     * 获取连接
     *
     * @return 连接实体
     */
    public DBConnection getConnection() {
        try {
            semaphore.acquire(); //获取一个许可,信号量减一
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DBConnection conn = null;
        synchronized (connPoolList) {
            //同步获取一个连接
            conn = connPoolList.removeFirst(); //从集合中删除并返回第一个元素
        }
        return conn;
    }

    /**
     * 释放连接
     *
     * @param conn 连接
     */
    public void releaseConnection(DBConnection conn) {
        synchronized (connPoolList) {
            connPoolList.addLast(conn); //将指定的元素追加到此集合的末尾。
        }
        semaphore.release();  //释放许可,信号量加一
    }
}


测试类:

package com.alex.semaphore;

/**
 * @author: alex
 * @Date: 2019/3/20
 * @Description: 模拟场景:数据库连接池的大小为2,当有3个线程同时请求获取连接时,有2个请求可以获得连接池,1个请求处于等待状态。
 * 当有连接归还后,处于等待的请求即可获得连接。
 */
public class DBConnectionTest {

    public static void main(String[] args) {
        DBConnectionPool pool = new DBConnectionPool(2);
        /**
         * 开启3个线程请求分配连接
         */
        for (int i = 0; i < 3; i++) {
            new Thread() {
                public void run() {
                    try {
                        System.out.println("线程" + Thread.currentThread().getName() + "准备获取数据库连接...");
                        DBConnection connection = pool.getConnection();
                        System.out.println("线程" + Thread.currentThread().getName() + "拿到数据库连接:" + connection.getId());
                        //模拟处理业务逻辑,每个连接使用的时间不相等
                        int index = Integer.valueOf(connection.getId().split("_")[1]);
                        Thread.sleep(1000 * index);
                        pool.releaseConnection(connection);
                        System.out.println("线程" + Thread.currentThread().getName() + "归还数据库连接...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }
}

运行结果:

线程Thread-0准备获取数据库连接...
线程Thread-1准备获取数据库连接...
线程Thread-0拿到数据库连接:conn_1
线程Thread-2准备获取数据库连接...
线程Thread-1拿到数据库连接:conn_0
线程Thread-1归还数据库连接...
线程Thread-2拿到数据库连接:conn_0
线程Thread-2归还数据库连接...
线程Thread-0归还数据库连接...

都是一些工具类的简单使用。配合api就可以看懂,不做过多的解释。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值