- List item
- 线程池是一种多线程的处理机制,当任务添加到线程池当中的时候会被添加到任务队列当中,当线程创建并启动的时候,会自动的执行处理这些任务。这里的任务是指我们用runnable接口和callable接口实现的线程任务。
- 程序当中多个线程存在的时候不方便管理,即使任务闲置任务还在运行
- 如果任务较多,闲置线程销毁,新的任务线程在重新生成的时间耗费较大
- 线程池可以重复的利用线程,提高了效率和资源的合理利用性
- 线程和任务分离,提高线程的重复利用率
- 控制线程并发数量;降低服务器的压力;统一管理所有的线程
- 资源消耗减少(不用重复的消耗创建线程)
- 响应速度加快(直接讲线程放入任务队列当中,加快了任务执行的效率)–假如创建线程速度t1,执行任务速度t2,销毁线程速度t3,利用线程池免去了t1和t3任务执行的时间
- 系统更加稳定(线程是一种重要的资源,线程池可以统一的调度,监控,分配)
import java.util.LinkedList;
import java.util.List;
public class ThreadPool {
//保存任务的任务队列
private List<Runnable> runnable =new LinkedList<>();
//保存核心线程的线程队列
private List<WorkThread> worklist =new LinkedList<>();
public ThreadPool(int i)//输入参数代表创建几个核心的员工线程
{
for(int j=0;j<i;j++)
{
//只需要将任务列表传递给工作类即可
WorkThread wk =new WorkThread(runnable);
wk.start();
worklist.add(wk);
}
}
//线程池还有就是将任务提交到任务列表的方法
//为啥要使用线程安全相关的代码synchronized,因为当核心工作线程创建的时候,添加这个动作可能会被
//多个线程执行,当多个动作对同一个 *** 作对象进行 *** 作的时候就要运用到线程安全相关的知识、多个动作 *** 作一个对象(这个动作就要加上线程安全相关方法)
public void addwork(Runnable r)
{ //无论是消费者还是生产者都只能顺序的一个一个拿到执行权
//多个 *** 作的对象,作为线程锁
synchronized (runnable)
{
runnable.add(r);
//每次添加完毕以后高速,工作线程有任务了唤醒工作线程
//释放锁的条件:当代码块中的代码执行完毕;遇到同步锁的wait方法;代码块当中遇到return返回的时候
runnable.notify();
}
}
}
(2)WorkThread核心线程类的实现
import java.util.List;
//该类的作用是:执行任务队列当中的任务
public class WorkThread extends Thread{
private List<Runnable> runnable;
public WorkThread(List<Runnable> runnable) {
// TODO Auto-generated constructor stub
this.runnable =runnable;
}
//就是处理任务的代码块
public void run()
{
Runnable r=null;
while(true)
{
synchronized (runnable) {
while(runnable.size()<=0)
{
//当任务队列当中没有任务的时候,拿到锁的线程释放锁wait(),在线程等待的过程当中,有了任务以后,就会唤醒刚刚wait等待的锁继续执行
try {
runnable.wait();
System.out.println("线程"+Thread.currentThread().getName()+"进入等待状态");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
r=runnable.remove(0);
}//锁的释放并不代表执行权的释放,锁释放以后还是继续执行r.run() *** 作
//锁释放以后又会
//执行任务
r.run();
System.out.println("线程"+Thread.currentThread().getName()+"执行完任务");
}
}
}
(3)Test类的实现
package com.lk.ThreadPool0423;
public class Test {
public static void main(String[] args) {
//测试只需要创建线程池和添加任务即可(上传任务)
System.out.print("启动任务");
ThreadPool tp=new ThreadPool(5);//创建了一个内核五个线程的线程池
for(int i=0;i<20;i++)
{
Work work =new Work(i);
tp.addwork(work);
}
}
}
class Work implements Runnable
{
int id;
public Work(int i)
{
this.id=i;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在执行任务 "+id);
}
}
(4)执行效果展示
2 第二种自定义线程池的实现方法
(1)ThreadPool类的实现
package com.lk.PoolThread0421;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
//线程池需要有:线程数,核心线程数,最大线程数,队列
//功能有提交和执行的作用
public class ThreadPool {
int num;
int coresize;
int maxsize;
int listsize;
public List<Runnable> lists=Collections.synchronizedList(new LinkedList<>());
/**
* @param coresize
* @param maxsize
* @param listsize
* @param lists
*/
public ThreadPool(int coresize, int maxsize, int listsize) {
super();
this.coresize = coresize;
this.maxsize = maxsize;
this.listsize = listsize;
}
/**
* @param coresize
* @param maxsize
* @param lists
*/
public ThreadPool(int coresize, int maxsize, List<Runnable> lists) {
super();
this.coresize = coresize;
this.maxsize = maxsize;
this.lists = lists;
}
//将任务提交给任务队列,然后并执行该任务
public void submit(Runnable r)
{
if(lists.size()>listsize)
{
System.out.println("任务"+r+"被丢弃了");
}
else
{
lists.add(r);
//执行任务
exec(r);
}
}
public void exec(Runnable r)
{
if(num<coresize)
{
new Workers("核心线程1", lists).start();
num++;
}else if(num<maxsize)
{
new Workers("核心线程2",lists).start();
num++;
}
else
{
//因为r改了toString 里面的内容所以,r再加字符串的时候自动变化为字符
System.out.println("任务"+r+"已经被缓存了");
}
}
}
(2)Tasks类的实现
package com.lk.PoolThread0421;
//任务参数id
//执行一个消耗大概两秒 *** 作的任务
public class Tasks implements Runnable{
int id;
//快速的有参构造函数
/**
* @param id
*/
public Tasks(int id) {
super();
this.id = id;
}
@Override
public void run() {
// TODO Auto-generated method stub
//看看现在这个Runnable接口实现的线程依附于那个线程实现
String name =Thread.currentThread().getName();
System.out.println("线程"+name+"即将执行任务"+id);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程"+name+"完成任务:"+id);
}
//当打印这个类对象的时候显示这个值
public String toString()
{
return "{Task:"+id+"}";
}
}
(3) Workers类的实现
package com.lk.PoolThread0421;
import java.util.List;
//类的作用,从队列当中取出数据运行 *** 作
//这里用Thread的原因是runnable必须依附于thread执行,刚好和任务的线程接口对应
public class Workers extends Thread{
//保存名字,比如核心线程与否
public String name;
public List<Runnable> tasks;
/**
* @param name
* @param tasks
*/
public Workers(String name, List<Runnable> tasks) {
super();
this.name = name;
this.tasks = tasks;
}
@Override
public void run() {
// TODO Auto-generated method stub
//当队列当中有任务从队列当中取出来执行即可
if(tasks.size()>0)
{
Runnable r=tasks.remove(0);
r.run();
}
}
}
(4).Test类的实现
package com.lk.PoolThread0421;
public class Test {
public static void main(String[] args) {
//
ThreadPool tp=new ThreadPool(2,4,20);
for(int i=0;i<30;i++)
{
Tasks t=new Tasks(i);
tp.submit(t);//任务上传给线程池
}
}
}
(5)运行效果展示
三:JAVA内置线程池参数的理解
观察ThreadPoolExecutor的源码来了解线程池的工作原理
-举一个例子来简单说明一下JAVA内置线程池参数的理解
假设线程池的核心线程数2,最大线程数3,任务队列是1,饱和处理机制:是任务队列满了以后丢弃
- a客户(任务)去银行(线程池)办理业务,银行还没开始营业,则代表线程池当中的线程的数量是零,这个时候银行管理者安排一个业务员去窗口上给a办理业务
- b客户来到银行也做同样的处理(管理者再次安排一个核心业务员(核心线程)到窗口进行工作)
- c客户到来的时候,因为a,b客户都在办理业务(无空闲核心线程),所以c在银行大厅(任务队列)坐着等待
- d客户来到银行,这个时候无窗口(无核心线程),无空闲的座位(任务队列已满),银行管理者安排一个临时工业务员3站在大厅给d客户办理业务(最大线程数-核心线程数量)
- e客户来到银行以后吗,啥都是满的,就按照饱和处理机制来处理e客户(不接待e客户)
- 当临时工接待完d客户以后,等待的时间超过最大等待时间的时候,临时工下去了(销毁相关线程),但是正式的窗口的正式工要一直在哪里等着,等待新的客户(任务)的到来
- 注意这里最大空闲时间:非核心线程空闲多少时间以后(单位由时间单位unit决定),会销毁非核心线程
见下一篇博客
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)