小技巧

java线程池

2018-08-13  本文已影响384人  杨柳滔滔

一、线程池的作用

Thread其实是一种特别重量级的资源,创建、启动、销毁其实都是比较耗费系统资源的,因此对于线程的重复利用是一种特别好的编程习惯,加之程序中可创建的线程数量是有限的,一般系统的性能越好,可以创建的线程数目就越多。但是当线程创建的越多时,系统的性能就会越差。自JDK1.5起,Util包就提供了ExecutorService线程池的实现,主要目的是为了重复利用线程,提高系统的效率。

二、线程池的原理

线程池,就好比有一个大池子,里面装着已经创建好的线程,当有任务交给线程池执行的话,池中的某个线程会执行该任务。如果任务量太大,而池中的线程又不够的情况下,则需要重新扩充新的线程到线程池中,但是数量是有限的,因为池子是有容量的,不能无限去扩充。当任务比较少的时候,池中的线程会自动回收,不然占着不必要的系统资源。为了能够异步去提交任务和缓冲未被处理的任务,需要有一个任务队列。

问题:完整的线程池需要包含哪些东西???

三、线程池的实现

我们通过写代码的形式来实现一个简单的ThreadPool(线程池),虽然简单,但是功能基本具备。我们先来看一下线程的实现类图。


线程池实现类图.png

1.ThreadPool

主要定义了ThreadPool应具备的基本操作和方法
package com.lntu.zlt;

public interface ThreadPool {

// 提交任务到线程池
void execute(Runnable runnable);

// 关闭线程池
void shutdown();

// 获取线程池的初始化大小
int getInitSize();

// 获取线程池最大的线程数
int getMaxSize();

// 获取线程池的核心线程数量
int getCoreSize();

// 获取线程池中用于缓存队列任务的大小
int getQueueSize();

// 获取线程池中活跃线程的数量
int getActiveCount();

// 查看线程池是否已经被shutdown
boolean isShutdown();
}

2.RunnableQueue

RunnableQueue主要存放提交的Runnable,该Runnable是一个BlockedQueue,并有limit限制。

 package com.lntu.zlt;

public interface RunnableQueue {
// 将任务提交到队列中,有新的任务进来时首先会offer到队列中
void offer(Runnable runnable);

// 工作线程通过take()方法获取Runnable,从队列中获取相应的任务。
Runnable take();

// 获取任务队列中当前Runnable的数量
int size();

  }

3.ThreadFactory

ThreadFactory提供了创建线程的接口,个性化设置Thread,比如加入到哪个Group里面,优先级,Thread名字。

 package com.lntu.zlt;
//创建线程的工厂
 @FunctionalInterface
 public interface ThreadFactory {
// 用于创建线程
Thread createThread(Runnable runnable);
  }

4.DenyPolicy

DenyPolicy主要用于当Queue中的Runnable达到了limit上限的话,决定采用哪种策略通知提交者。

package com.lntu.zlt;

@FunctionalInterface
public interface DenyPolicy {
void reject(Runnable runnable, ThreadPool threadPool);

// 该策略会直接将任务丢弃
class DiscardDenyPolicy implements DenyPolicy {

    @Override
    public void reject(Runnable runnable, ThreadPool threadPool) {
        // TODO Auto-generated method stub
        // do nothing

    }
}

// 该拒绝策略会向任务提交者抛出异常
class AbortDenyPolicy implements DenyPolicy {

    @Override
    public void reject(Runnable runnable, ThreadPool threadPool) {
        // TODO Auto-generated method stub
        throw new RunnableDenyException("The runnable" + runnable + "will be abort");
    }

}

// 该拒绝策略会使任务在提交者所在的线程中执行任务
class RunnerDenyPolicy implements DenyPolicy {

    @Override
    public void reject(Runnable runnable, ThreadPool threadPool) {
        // TODO Auto-generated method stub
        if (!threadPool.isShutdown()) {
            runnable.run();
        }
    }

}
 }

5.RunnableDenyException

RunnableDenyException是RuntimeException的子类,他主要通知任务的提交者,任务队列已经无法再接收新的任务。

package com.lntu.zlt;
public class RunnableDenyException extends RuntimeException {
public RunnableDenyException(String message) {
    // TODO Auto-generated constructor stub
    super(message);
}
}

6.InternalTask

InternalTask是Runnable接口的实现,那么大家应该能够知道他是干嘛的了。该类会读取RunnableQueue,然后不断从queue中读取出某个Runnable,然后执行Runnable的run方法

package com.lntu.zlt;

public class InternalTask implements Runnable {
private final RunnableQueue runnableQueue;
private volatile boolean running = true;

public InternalTask(RunnableQueue runnableQueue) {
    this.runnableQueue = runnableQueue;
}

@Override
public void run() {
    // 如果当前任务为running并且没有被中断,则其不断地从queue中获取runnable,然后执行润方法
    while (running && !Thread.currentThread().isInterrupted()) {
        try {
            Runnable task = runnableQueue.take();
            task.run();
        } catch (InterruptedException e) {
            // TODO: handle exception
            running = false;
            break;
        }

    }

}

// 停止当前任务,主要会在线程池的shutdown方法中使用
public void stop() {
    this.running = false;
}
}

四、线程池面试题

这块转子一个简书作者,他这篇帖子写的比较细。
作者:闽越布衣
链接:https://www.jianshu.com/p/f84762a42512
來源:简书

上一篇 下一篇

猜你喜欢

热点阅读