本文共 6386 字,大约阅读时间需要 21 分钟。
在了解线程池之前,首先我们先了解什么是线程
在JAVA中,有两种方式创建线程
1、实现Runnable接口,实例化Thread;2 、继承Thread类,重写run()方法
区别:
Thread需要实现Runnable ,Runnable没有start()方法,只有Thread类中才有
(该段摘自百度)
http://wenku.baidu.com/link?url=Nxc165sfKCfnRuCnkZnNGNfF5ReG0tHU5cuYf-nrwhXnt-dX7ANAri-sjFUR_XfENJd-zBzKqIUvy5axb6V--vv8akTUV6AffaqGR5Xg1BC
在实际开发中一个多线程的操作很少使用Thread类,而是通过Runnable接口完成。
1、避免点继承的局限,一个类可以继承多个接口。2、适合于资源的共享以常见的卖票为例
A: 通过Thread 类完成:
首先,定义一个窗口用于卖票的线程public class MyThread extends Thread{ private int count =10; private String name ; public MyThread(String name){ this.name = name; } @Override public void run() { // TODO Auto-generated method stub for(int i = 0;i<20;i++){ //i 表示该窗口卖出的张数对应的人的位数 if(this.count>0){ System.out.println(this.name+"買到第:"+count--+"張票"); } } }}接着,创建三个线程,同时卖票,我们看看会有什么样的结果,代码如下
public class TicketThread { public static void main(String[] args) { MyThread m1 = new MyThread("one"); MyThread m2 = new MyThread("two"); MyThread m3 = new MyThread("three"); m1.start(); m2.start(); m3.start(); }}三个线程开启后,控制台输出的结果如下:
two買到第:10張票three買到第:10張票one買到第:10張票three買到第:9張票two買到第:9張票three買到第:8張票one買到第:9張票three買到第:7張票two買到第:8張票three買到第:6張票one買到第:8張票one買到第:7張票three買到第:5張票two買到第:7張票three買到第:4張票one買到第:6張票three買到第:3張票two買到第:6張票three買到第:2張票one買到第:5張票three買到第:1張票two買到第:5張票one買到第:4張票two買到第:4張票one買到第:3張票two買到第:3張票one買到第:2張票two買到第:2張票one買到第:1張票two買到第:1張票很明显,三个线程都默认10张票归自己所有,当三个线程开启后,一个卖出了30张票,线程与线程之间并没有进行数据的交互
现在我们实现第二种方案:实现Runnable 接口
同样的,让我们的MyThread 实现Runnable 接口public class MyThread implements Runnable{private int count = 10; @Override public void run() { // TODO Auto-generated method stub for(int i = 10;i<20;i++){ synchronized (this)//同步 { if(this.count>0){ System.out.println("買到第:"+count--+"張票"); } } } } }相对应的操作类
public class TicketThread { public static void main(String[] args) { MyThread thread = new MyThread(); new Thread(thread).start(); new Thread(thread).start(); new Thread(thread).start(); }}再来看一下输出的结果:
買到第:10張票買到第:9張票買到第:8張票買到第:7張票買到第:6張票買到第:5張票買到第:4張票買到第:3張票買到第:2張票買到第:1張票---------------------------------------------------------------华丽的分割线----------------------------------------------------------------------
现在了解了Java中的线程,现在我们就进一步了解更难的知识
线程池
同样的,我们先了解一下什么是线程池
为什么要使用线程池:
1、开发者可以重复使用线程池中的线程,避免不必要的创建与销毁;
2、可以对线程进行一些简单的操作,例如时间的控制等;
3、控制线程的数量,避免大量线程并发时造成内存的损耗
一个线程执行任务所需要的时间为:创建时间+执行任务时间+销毁时间
若滥用线程,则容易导致不必要的浪费。线程池的使用正是减少了创建和销毁线程的时间,从而达到节省开销的目的。
现在,我们就来了解下线程池
线程池的构造方法:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue这里提一下RejectedExecutionHandlerworkQueue) 用给定的初始参数和默认的线程工厂及被拒绝的执行处理程序创建新的 ThreadPoolExecutor。使用 工厂方法之一比使用此通用构造方法方便得多。 参数: corePoolSize - 池中所保存的线程数,包括空闲线程。 maximumPoolSize - 池中允许的最大线程数。 keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。 unit - keepAliveTime 参数的时间单位。 workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。 抛出: - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。 - 如果 workQueue 为 null public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) 用给定的初始参数和默认被拒绝的执行处理程序创建新的 ThreadPoolExecutor。 参数: corePoolSize - 池中所保存的线程数,包括空闲线程。 maximumPoolSize - 池中允许的最大线程数。 keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。 unit - keepAliveTime 参数的时间单位。 workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。 threadFactory - 执行程序创建新线程时使用的工厂。 抛出: - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。 - 如果 workQueue 或 threadFactory 为 null。 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) 参数: corePoolSize - 池中所保存的线程数,包括空闲线程。 maximumPoolSize - 池中允许的最大线程数。 keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。 unit - keepAliveTime 参数的时间单位。 workQueue - 执行前用于保持任务的队列。此队列仅由保持 execute 方法提交的 Runnable 任务。 handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。 抛出: - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。 - 如果 workQueue 或 handler 为 null。 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 参数: corePoolSize - 池中所保存的线程数,包括空闲线程。 maximumPoolSize - 池中允许的最大线程数。 keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。 unit - keepAliveTime 参数的时间单位。 workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。 threadFactory - 执行程序创建新线程时使用的工厂。 handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。 抛出: - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。 - 如果 workQueue、 threadFactory 或 handler 为 null。
这是程池对拒绝任务的处理策略。一般是队列已满或者无法成功执行任务,这时ThreadPoolExecutor会调用handler的rejectedExecution方法来通知调用者
默认有四个拒绝策略
1、ThreadPoolExecutor.AbortPolicy() 直接抛出异常RejectedExecutionException 2、ThreadPoolExecutor.CallerRunsPolicy() 直接调用run方法并且阻塞执行 3、ThreadPoolExecutor.DiscardPolicy() 直接丢弃后来的任务 4、ThreadPoolExecutor.DiscardOldestPolicy() 丢弃在队列中队首的任务
官方定义的四种线程池
转载地址:http://wsbbb.baihongyu.com/