线程池的使用

来源:互联网 发布:自考师范本科 知乎 编辑:程序博客网 时间:2024/06/05 17:06

参考:

Java四种线程池的使用

Java多线程总结之线程安全队列Queue

Android 线程池来管理线程

java&android线程池-Executor框架之ThreadPoolExcutor&ScheduledThreadPoolExecutor浅析(多线程编程之三)

并行和并发区别

1、并行是指两者同时执行一件事,比如赛跑,两个人都在不停的往前跑;

2、并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率

new Thread的弊端如下:

a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。

相比new Thread,Java提供的四种线程池的好处在于:

a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

线程池的作用:

线程池作用就是限制系统中执行线程的数量。

根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排 队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池 中有等待的工作线程,就可以开始运行了;否则进入等待队列。

为什么要用线程池:

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

ThreadPoolExecutor相关类的关系:

    public interface Executor {}        //真正的线程池接口。        public interface ExecutorService extends Executor {}            //能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。            public interface ScheduledExecutorService extends ExecutorService {}            public abstract class AbstractExecutorService implements ExecutorService {}                //ExecutorService的默认实现。                public class ThreadPoolExecutor extends AbstractExecutorService {}                    //继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。                    public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {                private static class DelegatedExecutorService extends AbstractExecutorService {                    private static class FinalizableDelegatedExecutorService extends DelegatedExecutorService {

ThreadPoolExecutor的构造方法:

    public ThreadPoolExecutor(                int corePoolSize,//核心线程数,能够同时执行的任务数量;                int maximumPoolSize,//最大线程数,达到最大任务数新任务将会被阻塞;                long keepAliveTime,//线程没有任务执行时最多保持多久时间会终止,然后线程池的数目维持在corePoolSize 大小,在corePore<*<maxPoolSize情况下有用                TimeUnit unit,//时间单位;                BlockingQueue<Runnable> workQueue,//阻塞队列用来存储等待执行的任务,当前对线程的需求超过了corePoolSize大小才会放在这里                ThreadFactory threadFactory,//创建线程的工厂,使用系统默认的类,主要用来创建线程,比如可以指定线程的名字;                RejectedExecutionHandler handler) {//当任务数超过maximumPoolSize时,对任务的处理策略,默认策略是拒绝添加;        if (corePoolSize < 0 ||                maximumPoolSize <= 0 ||                maximumPoolSize < corePoolSize ||                keepAliveTime < 0)            throw new IllegalArgumentException();        if (workQueue == null || threadFactory == null || handler == null)            throw new NullPointerException();        this.corePoolSize = corePoolSize;        this.maximumPoolSize = maximumPoolSize;        this.workQueue = workQueue;        this.keepAliveTime = unit.toNanos(keepAliveTime);        this.threadFactory = threadFactory;        this.handler = handler;    }
  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
  2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
    1. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
    2. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
    3. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
    4. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
  3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
  4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

这样的过程说明,并不是先加入任务就一定会先执行。
假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4~13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17~20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。

处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。一、currentSize < corePoolSize空闲线程新线程(优先)二、corePoolSize < currentSize < maximumPoolSizeworkQueue未满时,添加进来的任务会被安排到workQueue中等待执行。 workQueue已满时,会立即开启一个非核心线程来执行任务。     空闲线程(优先):超过一定的时间(keepAliveTime)时会被回收    新线程三、currentSize > maximumPoolSize调用handler默认抛出RejectExecutionExpection异常。

FixedThreadPool
是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。
但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。

    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {        return new ThreadPoolExecutor(nThreads, nThreads,//线程池中均为核心线程,最多线程数nThreads                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>(),//单向链表实现的阻塞队列,先进先出的顺序,可无限排队                                      threadFactory);    }

CachedThreadPool
的特点就是在线程池空闲时,即线程池中没有可运行任务时,它会释放工作线程,从而释放工作线程所占用的资源。
但是,但当出现新任务时,又要创建一新的工作线程,又要一定的系统开销。
并且,在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。

    public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//线程池中均为非核心线程,而且可无限创建线程                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());//如果现有线程无法接收任务,将会创建新线程来执行.    }

参考:Java线程池ThreadPoolExecutor详解

四种线程池:

Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果超过存活时间不活动,其会自动被终止。最大线程数不限    new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>())newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。    new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。最大线程数不限    super(corePoolSize, Integer.MAX_VALUE , DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue())newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。    new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

队列

//    队列:先进先出    public interface BlockingQueue<E> extends Queue<E> {    public interface TransferQueue<E> extends BlockingQueue<E> {    public abstract class AbstractQueue<E> extends AbstractCollection<E> implements Queue<E> {          /*阻塞队列,线程安全*/          public class SynchronousQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable {              //一个不存储元素的阻塞队列。          }          public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable {              //一个由数组结构组成的有界阻塞队列。          }          public class PriorityBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable {              //一个支持优先级排序的无界阻塞队列。          }          public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable {              //一个由链表结构组成的有界阻塞队列。          }          public class LinkedTransferQueue<E> extends AbstractQueue<E> implements TransferQueue<E>, Serializable {              //一个由链表结构组成的无界阻塞队列。          }          public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingDeque<E>, Serializable {              //一个由链表结构组成的双向阻塞队列          }          public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> {              //一个使用优先级队列实现的无界阻塞队列          }          /*非阻塞队列*/          public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, Serializable {              //并发队列,基于链接节点的、无界的、线程安全。          }

线程池提交之execute和submit区别:

向线程池提交任务有两种方式:

      Executor.execute(Runnable command);      ExecutorService.submit(Callable<T> task);

参考:线程池提交之execute和submit区别

1.对返回值的处理不同

execute方法不关心返回值。

submit方法有返回值,Future.

2.对异常的处理不同

excute方法会抛出异常。

sumbit方法不会抛出异常。除非你调用Future.get()

线程池工具类:

/** * 线程池工具类 * <p> * 根据CPU数量 */public class ThreadPoolManager {    private ThreadPoolExecutor executor;    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;//9    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//17    private static final int KEEP_ALIVE = 1;    private static ThreadPoolManager mInstance;    public static ThreadPoolManager getInstance() {        if (mInstance == null) {            synchronized (ThreadPoolManager.class) {                if (mInstance == null) {                    mInstance = new ThreadPoolManager();                }            }        }        return mInstance;    }    private ThreadPoolManager() {        executor = new ThreadPoolExecutor(                CORE_POOL_SIZE,                MAXIMUM_POOL_SIZE,                KEEP_ALIVE,                TimeUnit.SECONDS,                new LinkedBlockingQueue<Runnable>(),                Executors.defaultThreadFactory(),                new ThreadPoolExecutor.AbortPolicy()        );    }    /**     * 执行任务     */    public void execute(Runnable runnable) {        if (runnable == null) return;        executor.execute(runnable);    }    /**     * 移除任务     * <p>     * 注意:此方法起作用有一个必要的前提,就是这个任务还没有开始执行,如果已经开始执行了,就停止不了该任务了,这个方法就不会起作用     */    public void remove(Runnable runnable) {        if (runnable == null) return;        executor.remove(runnable);    }    /**     * 提交任务     */    public Future<?> submit(Runnable runnable) {        if (runnable == null) return null;        return executor.submit(runnable);    }}

调用:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        for (int i = 0; i < 9; i++) {            ThreadPoolManager.getInstance().execute(new Runnable() {                @Override                public void run() {                    SystemClock.sleep(5000); //模拟延时执行的时间                }            });        }    }}
原创粉丝点击