线程池的使用
来源:互联网 发布:自考师范本科 知乎 编辑:程序博客网 时间: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; }
- 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
- 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
- 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
- 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
- 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
- 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
- 当一个线程完成任务时,它会从队列中取下一个任务来执行。
- 当一个线程无事可做,超过一定的时间(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); //模拟延时执行的时间 } }); } }}
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 命令模式(Command)-----基于JAVA语言
- ContextLoader获取bean实例
- 程序人生
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- Android侧滑-DrawerLayout
- 线程池的使用
- 模拟实现memcpy,memmove,memset
- Linux 安装Nginx详细图解教程
- 苹果开发者账号中,测试机器列表已达到100台上限,怎么办
- Android Studio生成apk安装返回失败ErrorCode:-15、INSTALL_FAILED_TEST_ONLY
- Lua中元方法__call的使用
- 01小项目
- live555 两个循环
- oracle新建用户相关操作