线程池的知识点

来源:互联网 发布:阿里云2m带宽并发数 编辑:程序博客网 时间:2024/06/06 20:01
* 线程池
* Executor接口(执行器)
* 里面有一个方法 void execute(Runnable command)//执行Runnable这个任务
*  ExecutorService接口(执行器服务,一堆执行器在等着扔任务,你扔了一个Runnable任务,执行器服务就帮我执行了)      
* 不光有execute()方法,还新增加了submit(Callable<T> task)和submit(Runnable task),也是提交任务的;callable汉语:可以被调用的
*  Callable<V>接口
* 里面有个call()方法,有返回值V(泛型),且可以抛出一个异常,而Runnable接口的run方法没有返回值,不能抛出异常
* Executors是一个工具类,相当于collections
*  
* ThreadPool线程池:一对线程,装在某个容器里,等着你来运行 
* ExecutorService service = Executors.newFixedThreadPool(5);创建一个固定大小的线程池,CPU有几个核至少起几个线程
     *  for(int i=0;i<6;i++){
service.execute(new Runnable(){ //这个地方可以有两种方式来执行任务,一个是execute()方法,一个是submit()方法,
public void run(){ //自动调用run()方法,线程执行完不会消失,未执行的任务放在任务队列里面(阻塞队列)
try {          //一个线程池维护两个队列,一个是未执行的队列,另一个结束的任务队列
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
);
}
service.shutdown()关闭线程池
service.isTerminated()线程池里面的任务是不是都执行完了
service.isShutdown() 线程池是不是关闭了,如果显示关了可能正在关闭的过程当中
*/
/**
* Future:用来拿到Callable的返回值
* FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>(){
public Integer call(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1000;
}
});
new Thread(task).start();//线程里面可以执行Callable任务,这个task位置,相当于里面call()方法代替了run()方法
System.out.println(task.get());//阻塞任务,一直等待程序结束拿到返回值才执行,这个get方法是拿返回值的方法
ExecutorService service = Executors.newFixedThreadPool(5);
Future<Integer> f =service.submit(new Callable<Integer>(){
public Integer call(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 1;
}
});
System.out.println(f.get());//阻塞,等待拿到返回值
System.out.println(f.isDone());//任务是否执行完
*/
/**
ExecutorService service = Executors.newCachedThreadPool();//缓存线程池,一开始一个线程都没有,来一个任务起一个线程,如果里面现在有两个线程,第三个任务来了,如果有一个线程空闲,则由空闲的线程执行这个任务
如果没有空闲线程,则继续启动新的线程,最对可以起几万个线程(根据你的电脑配置),默认一个线程空闲60s就自动销毁了(AliveTime)

ExecutorService service = Executors.newSingleThreadExecutor()//线程池里面只有一个线程,扔多少个任务都是一个线程执行,保证了线程的执行顺序
*/
/**(死该6的)计划中的 定时器线程池,替代Timer,线程池里面的可以复用,而Timer每次都要new一个新的线程
* ScheduledExecutorService service = Executors.newScheduledThreadPool(4); 适用于定时任务
* 以固定的频率来执行某个任务,4个参数,第一个参数是一个Runnable任务,第二个参数是延迟多长时间执行第一个任务,第三个参数是每隔多长时间执行一个任务,第四个参数是时间单位
* service.scheduleAtFixedRate(Runnable(),0,500,TimeUnit.MILLISECONDS);第一个任务马上执行,每隔500毫秒这个任务重复执行
*/
/**工作窃取线程,主动的找活干,根据你的CPU是几核,默认起多少个线程,任务窃取线程;适用于任务分配的不均匀的情况,可以去别的没执行完的任务队列里面去偷 1.8才有的
* 假设你起了4个线程,有5个任务,第一个线程干完了,会主动找活干,会主动执行第5个任务
* 本质上JoinPool
* ExecutorService service =Executors.newWorkStealingPool();
* 产生的精灵线程(后台线程,后台线程),主线程不阻塞的话看不到输出
*/
/**分叉,合并   大规则的数据计算  1.7之后才有的
* ForkJoinPool() 把一个难以完成的大任务,切分成一个一个的小任务1,2,3;如果这个小任务还是太大,还可以继续分fork,分成多小自己可以指定,如果还是大还可以继续分;分完之后把结果进行合并即join,产生一个
*                总的结果,而里面任务的切分自己可以指定,线程的启动根据你任务切分的规则由ForkJoinPool这个线程池自己来维护
*  一般来讲都是从ForkJoinTask<V>类来继承,但是直接写起来比较麻烦,大多数的情况下从RecursiveAction(rui克西爱克神),没有返回值,和RecursiveTask(rui克西task),有返回值,递归任务,因为它切分了还可以再切分
*  先说RecursiveAction,需要重写这个任务的void compute()方法 ,然后调用fork()方法,启动一个新的线程
*  ForkJoinPool fjp = new ForkJoinPool();
*  AddTask task = new AddTask(0,nums.length);
*  fjp.execute(task);
*  由于是精灵线程,还得整一个阻塞
*  System.in.read();
*  
*  如果从RecursiveTask<V>来继承,就得指定返回值了
*  重写Long compute()方法
*/
/**
* 线程池背后的原理:其实线程池背后调用的都是ThreadPoolExecutor(除了工作窃取线程和分叉合并线程,继承自ExecutorService)
* ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,Long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue);
* 第一个参数是你自己指定有多少个线程
* 第二个参数是最多可以装多少个线程
* 第三个参数是这个线程呆多长时间没有人理他,他就会消失
* 第四个参数是第三个参数的单位
* 第五个参数真正的装任务的容器,都是阻塞式的,任务来了之后可以自己去取
* 1:FixedThreadPool(int nThreads) 0L表示这个线程永远不会消失
*         new ThreadPoolExecutors(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())
* 2:CachedThreadPool()
*   new ThreadPoolExecutors(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronizedQueue<Runnable>());
* 3:SingleThreadPool()
*         new ThreadPoolExecutors(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())
* 4:SchedulePool(int corePoolSize)
*   super(corePoolSize,Integer.MAX_VALUE,0,TimeUnit.MILLISECONDS,new DelayedWorkQueue())
* 如果想要自己去定义自己的线程池,就可以自己去new ThreadPoolExecutors()里面的参数
*/
/**
* java8新增
* ParallelStreamAPI(pawolou) 
* 将100万个数看成是一个数据流,用多线程的方式去访问里面的数,共同的计算
* List list = new ArrayList();
* list.parallelStream().forEach(方法)
*/
原创粉丝点击