为什么要使用线程池 1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。创建线程关闭线程花销是比较大的。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。 (参考 https://www.zhihu.com/question/41134816/answer/1086805195 )
线程池的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class UseThreadPool { static class Worker implements Runnable { private String taskName; private Random r = new Random(); public Worker (String taskName) { this .taskName = taskName; } public String getName () { return taskName; } @Override public void run () { System.out.println(Thread.currentThread().getName() +" process the task : " + taskName); SleepTools.ms(r.nextInt(100 )*5 ); } } static class CallWorker implements Callable <String > { private String taskName; private Random r = new Random(); public CallWorker (String taskName) { this .taskName = taskName; } public String getName () { return taskName; } @Override public String call () throws Exception { System.out.println(Thread.currentThread().getName() +" process the task : " + taskName); return Thread.currentThread().getName()+":" +r.nextInt(100 )*5 ; } } public static void main (String[] args) throws InterruptedException, ExecutionException { ExecutorService pool = new ThreadPoolExecutor(2 ,4 ,3 ,TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10 ), new ThreadPoolExecutor.DiscardOldestPolicy()); for (int i=0 ;i<6 ;i++) { Worker worker = new Worker("worker_" +i); pool.execute(worker); } for (int i=0 ;i<6 ;i++) { CallWorker callWorker = new CallWorker("callWorker_" +i); Future<String> result = pool.submit(callWorker); System.out.println(result.get()); } pool.shutdown(); } }
线程池中几个参数的含义 1 2 3 4 5 6 7 8 ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>(), Executors.defaultThreadFactory(), new AbortPolicy() );
四种拒绝策略 CallerRunsPolicy : 当线程池和队列都满时,任务将会被任务的调用方线程执行,如果线程池关闭,那么任务将会被抛弃 AbortPolicy :当线程池和队列都满时,再有任务进来直接抛出RejectedExecutionException异常 DiscardPolicy: 当线程池和队列都满时,再有任务进来,默默的将任务抛弃 DiscardOldestPolicy: 当线程池和队列都满时,再有任务进来,抛弃最老的未处理的任务即当前队列中排在最前面的任务,然后重试该新进来的任务,如果线程池关闭,那么任务将会被抛弃
阻塞队列BlockingQueue add(Object): 把 Object 加到 BlockingQueue 里,即如果 BlockingQueue 可以容纳,则返回 true, 否则招聘异常
offer(Object): 表示如果可能的话,将 Object 加到 BlockingQueue 里, 即如果 BlockingQueue 可以容纳,则返回true,否则返回false.
put(anObject): 把 Object 加到 BlockingQueue 里, 如果 BlockQueue 没有空间,则调用此方法的线程被阻塞 直到BlockingQueue里面有空间再继续.
poll(time): 取走 BlockingQueue 里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null
take(): 取走 BlockingQueue 里排在首位的对象,若 BlockingQueue 为空, 阻塞 进入等待状态直到Blocking有新的对象被加入为止
核心线程数的设置 任务类型: cpu密集型 不要超过cpu并行线程数:Runtime.getRuntime().availableProcessors()+1
io密集型 Runtime.getRuntime().availableProcessors() x2
线程进入顺序 corePoolSize —> BlockingQueue —> maximumPoolSize
若最大线程数也满了,再进入的线程按设置的拒绝策略执行。