优雅的构建线程池,实施多线程抢票

1、构建线程池

package com.example.demo.juc;

import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadPoolFactory {

    private static ThreadPoolExecutor pool;
    private static final ReentrantLock lock = new ReentrantLock();
    public static ExecutorService inintThreadPool() {

        lock.lock();
        try {
            if (pool == null) {
                pool = createThreadPool();
            }
        } catch ( Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

        return pool;
    }

    /**
     * corePoolSize – 要保留在池中的线程数,即使它们处于空闲状态,除非 allowCoreThreadTimeOut 已设置 maximumPoolSize – 池中允许的最大线程数
     * keepAliveTime – 当线程数大于核心数时,这是多余的空闲线程在终止之前等待新任务的最长时间。
     * unit – 参数的时间 keepAliveTime 单位 workQueue – 用于在执行任务之前保留任务的队列。
     * 此队列将仅 Runnable 保存该方法提交 execute 的任务。 threadFactory – 执行器创建新线程时使用的工厂
     * @return
     */
    private static ThreadPoolExecutor createThreadPool() {
        /**
         * 有界
         * 默认的工作线程队列,当任务处理速度跟不上后,就会将其他的任务放入到工作线程
         */
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(5);

        /**
         * 可有可无界
         * 默认的工作线程队列,当任务处理速度跟不上后,就会将其他的任务放入到工作线程
         */
        BlockingQueue linkedBlockingDeque = new LinkedBlockingQueue<>();
        
        ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();

        /**
         * 
         */
        ThreadFactory threadFactory = Executors.defaultThreadFactory();

        return new ThreadPoolExecutor(
                3, 
                10,
                500, TimeUnit.MICROSECONDS,
                arrayBlockingQueue,
                threadFactory,
                abortPolicy);
    }
}
2、测试抢票的业务代码
package com.example.demo.juc;

import java.util.concurrent.ExecutorService;

public class ArrayBlockingQueueTest {
    
    static class MyThread extends Thread {

        /**
         * 票数
         */
        private static int tickets = 100;

        /**
         * 游标
         */
        private boolean flag = true;

        @Override
        public void run() {

            while (flag) {
                if (tickets < 1) {
                    flag= false;
                    return;
                }
                System.out.println("线程" + Thread.currentThread().getName() + ": 获取到抢票的权力,当前票数为: " + tickets);
                tickets --;
            }
        }
    }


    public static void main(String[] args) {

        Runnable t1 = new MyThread();
        Runnable t2 = new MyThread();
        Runnable t3 = new MyThread();
        Runnable t4 = new MyThread();

        ExecutorService threadPool = ThreadPoolFactory.inintThreadPool();
        threadPool.execute(t1);
        threadPool.execute(t2);
        threadPool.execute(t3);
        threadPool.execute(t4);

        /**
         * 任务执行完毕后,可以优雅的关闭线程池
         */
        threadPool.shutdown();

    }

}
3、输出的结果【有并发问题】
线程pool-1-thread-1: 获取到抢票的权力,当前票数为: 100
线程pool-1-thread-3: 获取到抢票的权力,当前票数为: 100
线程pool-1-thread-2: 获取到抢票的权力,当前票数为: 100
线程pool-1-thread-2: 获取到抢票的权力,当前票数为: 97
线程pool-1-thread-3: 获取到抢票的权力,当前票数为: 98
线程pool-1-thread-3: 获取到抢票的权力,当前票数为: 95
线程pool-1-thread-1: 获取到抢票的权力,当前票数为: 99
...
4、怎么回事,居然最后一张票,还是出现了并发问题,我也用了ReentrantLock呀?怎么无法搞定,是每次线程在实例化的时候都拿到了一把独立的锁吗?怎么解决这个问题?
5、这样?
private volatile ReentrantLock lock = new ReentrantLock();
6、这样?让锁单例?【可以解决】
private static ReentrantLock lock = new ReentrantLock();
####有没有其他姿势?

你可能感兴趣的:(java,jvm,开发语言)