线程池的基础知识

线程池的作用

线程是一种有限的宝贵的系统资源,创建线程需要很多时间和系统资源,需要对线程进行回收利用,降低对系统资源的消耗,提升服务器的执行效率。

几种常见的线程池

顶层接口:Executor

方法:execute(Runnable) 将任务交给线程池执行。

子接口:ExecutorService

方法:

1.shutdown() 停止线程池,会等待线程执行完。

2.shutdownNow() 停止线程池,会终止线程执行。

ExecutorService的子接口:ScheduledExecutorService

常用的方法:

在固定的延迟时间后执行

scheduleWithFixedDelay(执行的Runnable任务,初始的延迟,延迟,时间单位)

在固定的周期执行:

scheduleAtFixedRate(执行的Runnable任务,初始的延迟,周期,时间单位)

工具类:Executors 提供了几个静态方法,帮助方便的创建线程池。

 线程池的7个参数

线程池的实现类:ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

 优化配置的几种方式

1.核心线程数

和cpu核心数以及任务数量和执行时间相关。

核心线程数 = cpu核心数 * n ,n >= 1 上限和任务数以及执行时间相关。

2.最大线程数

最大线程数和核心线程数相同,减少系统创建线程和销毁线程的时间和资源,提高性能。

3.keepAliveTime

如果最大线程数和核心线程数相同,可以设置为0;

否则可以尽量大一点,减少系统创建线程和销毁线程的时间和资源。

4.BlockingQueue

设置为LinkedBlockQueue,任务经常添加和删除时,性能更高。

设置为SynchorousQueue,能处理的任务数更多,吞吐量更高(每秒处理请求数)。

线程池的原理

线程池总的执行流程

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

线程池的线程是如何回收?

 步骤:

1.通过线程池的execute执行任务。

2.通过调用线程池的addWorker方法添加工作线程。

3.同时把Runnable执行任务添加到workQueue中。

4.创建Worker添加到HashSet中,Worker中包含线程。

5.启动Worker中的线程。

6.线程调用runWorker方法。

7.runWorker中判断任务不为空就执行任务。

8. 任务如果为空,就调用getTask()方法取任务。

9.循环不断调用workerQueue阻塞队列的take()方法。

10.任务队列为空就自动阻塞当前线程,直到任务队列不为空唤醒线程去执行任务。

线程相关的工具类

CountDownLatch类

门栓,有时候一个线程的执行需要等待其它线程执行完后再执行。

创建:

new CountDownLatch(倒数的数字) 

常用的API:

void countDown() //倒数一次,数字减一
void await() //阻塞当前线程,当倒数为0就唤醒

 简单的使用案例


/**
 * CountDownLatch类
 */
public class CutDownLatchDemo {
    public static void main(String[] args) {
        //创建倒数对象
        CountDownLatch countDownLatch = new CountDownLatch(3);
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"等待别的线程执行完");
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"执行完毕");
        }).start();

        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                for (int j = 0; j < 5; j++) {
                    System.out.println(Thread.currentThread().getName()+"执行"+j);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //倒数一次
                countDownLatch.countDown();
                System.out.println(Thread.currentThread().getName()+"执行完毕,count="+countDownLatch.getCount());
            }).start();
        }
    }
}

Semaphore类

信号量,控制启动线程的数量。

创建:

new Semaphore(最大数量)

常用的API:

aquired() //请求一个信号量
release() //释放一个信号量

简单使用案例

/**
 * Semaphore类
 */
public class SemphoreDemo {
    public static void main(String[] args) {
        //创建信号量
        Semaphore semaphore = new Semaphore(5);
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //请求信号量
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"开始执行");
                try {
                    Thread.sleep(500);
                    //释放信号量
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值