线程基础----如何编写java线程池(二)

本贴最后更新于 3900 天前,其中的信息可能已经事过景迁

一、场景:

            在了解了线程状态的转换,以及java提供的线程调度的一些方法之后,我尝试写一个线程池。

二、线程池的优缺点

            (1)

                谈到高并发必然离不开线程池,因为他有如下的优点:

               1.1、降低资源的消耗。通过利用已创建的线程,来降低创建和销毁带了的消耗

               1.2、当任务到达时候,不需要创建线程就可以立即执行。

               1.3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。

           (2)线程池的缺点这里就不赘述了,可以 

                

三、如何编写线程池

 先贴出代码

  线程池主要代码

import java.util.LinkedList;
import java.util.List;

public class NewThreadPool {
volatile int counter =0;
private static int WORKNUM = 5;
List<Runnable> taskQueue = new LinkedList<Runnable>();

// 已处理的任务
private static volatile int finished_task = 0;
private WorkThread[] workThreads;
private static NewThreadPool newThreadPool;

private NewThreadPool(int workNum) {
	NewThreadPool.WORKNUM = workNum;
	// 定义一个工作线程数组
	workThreads = new WorkThread[workNum];
	for (int i = 0; i &lt; workThreads.length; i++) {
		workThreads[i] = new WorkThread();
		workThreads[i].start();
	}
}

// 单例模式获得默认线程个数的线程池
public static NewThreadPool getThreadPool() {
	return getNewThreadPool(NewThreadPool.WORKNUM);
}

// 获得传入参数个数的线程池,大小不能小于默认个数
public static NewThreadPool getNewThreadPool(int work_num) {
	if (work_num &lt;= 0) {
		work_num = NewThreadPool.WORKNUM;
	}
	if (null == newThreadPool) {
		newThreadPool = new NewThreadPool(work_num);
	}
	return newThreadPool;
}

//执行线程
public void execute(Runnable task){
	synchronized (taskQueue) {
		taskQueue.add(task);
		taskQueue.notify();
	}
}

//批量执行线程任务
public void execute(Runnable[] task){
	synchronized (taskQueue) {
		for(Runnable t : task ){
			taskQueue.add(t);
			taskQueue.notify();
		}
	}
}
public void execute(List&lt;Runnable&gt;task){
	synchronized (taskQueue) {
		for(Runnable t : task){
			taskQueue.add(t);
			taskQueue.notify();
		}
	}
}
//返回工作线程的个数
public int getWorkedThreadNumbers(){
	return WORKNUM;
}
//返回已经完成的线程任务
public int getFinishedTaskNumbers(){
	return finished_task;
}

//返回还没有完成任务的的线程个数
public int getWaitTaskNumbers(){
	return taskQueue.size();
}

//销毁线程池方法,等到所有线程都完成之后才会销毁
public void destory(){
	while(!taskQueue.isEmpty()){
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	for(int i=0;i&lt;WORKNUM;i++){
		workThreads[i].stopWorker();
		workThreads[i] = null;
	}
	newThreadPool = null;
	taskQueue.clear();
}
// 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数
	@Override
	public String toString() {
		return &quot;WorkThread number:&quot; + WORKNUM + &quot;  finished task number:&quot;
				+ finished_task + &quot;  wait task number:&quot; + getWaitTaskNumbers();
	}

// 工作线程
private class WorkThread extends Thread {
	private boolean isRunning = true;
	@Override
	public void run() {
		
		Runnable r = null;
		while (isRunning) {
			synchronized (taskQueue) {
				while (isRunning &amp;&amp; taskQueue.isEmpty()) {
					try {
						taskQueue.wait(20);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				// 由于是队列,取第0个
				if (!taskQueue.isEmpty()) {
					r = taskQueue.remove(0);
				}
			}
			if (null != r) {
				r.run();
				//stopWorker();
			}
			System.out.println(Thread.currentThread().getName() + &quot;------------&quot; + counter++  +&quot;-----&quot; + getWaitTaskNumbers());
			finished_task++;
			r = null;
		}
	}
	// 停止工作,让该线程自然执行完run方法,自然结束
	public void stopWorker() {
		isRunning = false;
	}
}

}

 以及测试demo

//测试线程池
public class TestThreadPool {
	public static void main(String[] args) {
		// 创建3个线程的线程池
		NewThreadPool t = NewThreadPool.getNewThreadPool(10);
		t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
		t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
		System.out.println(t);
		//t.destory();// 所有线程都执行完成才destory
		System.out.println(t);
		t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
}

// 任务类
static class Task implements Runnable {
	private static volatile int i = 1;

	@Override
	public void run() {// 执行任务
		System.out.println(&quot;任务 &quot; + (i++) + &quot; 完成&quot;);
	}
}

}

以上为线程池代码。参看了很多网友的博客,然后才理解了这个线程池的代码,然后按着理解写出了这个。如果发现有和网友代码有类似,不要惊奇,我是初学者请见谅。呵呵

(三)总结:

         在编写线程池的时候,我们需要有一个基本的思路。需要一个基本的思路,一个安全的线程队列用来存放线程。按照要求初始化默认数量的线程,并且启动它,让这些线程在等待队列中等待,然后当目标任务来时,将其唤醒获得锁然后处理目标任务。

         由于队列是不安全的,所以在线程添加到队列,和从队列中取出来的时候,都需要同步synchroniza,保证其安全。还有一个概念就是一旦线程池中run方法跑完,那么它的生命周期也就结束了。线程状态转换,参考 线程基础(详细介绍线程状态转换) ,所以再我们需要一个信号量,将工作线程的run方法中加上信号量,这样就可以保证,线程池中线程可以重用,只有当你销毁线程池的时候,所有线程才会销毁。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖
  • 多线程
    11 引用 • 26 回帖
  • 线程池
    3 引用 • 8 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...