线程池意义、原理解析及简单实现

〇.前言

本文适用于线程或线程池小白,或者是想了解线程池的程序猿和为面试做准备的同学。

本文知识来自于网课。

一.为什么要使用线程池

a.用多线程的目的是什么?

充分利用CPU,并发做多件事。

b.单核cpu适不适合用多线程?

适合,如果是单线程,线程中需要等待IO时,此时CPU就空闲出来了。

c.线程什么时候会让出cpu?

阻塞时 wait awaie 等待IO

sleep

yield

结束

d.线程是什么?

一条代码执行流,完成一组代码的执行。

这一组代码,我们往往成为一个任务。

e.cpu在做什么工作?

执行代码

小总结:任务(code)->被线程包装->运行到cpu上执行

f.线程是不是越多越好?

并不是!创建线程要占用很多内存。

①问:造线程要不要时间?一次性使用,用完了得销毁,销毁要不要耗时间?

答:线程在java中是一个对象,每一个java线程都需要一个操作系统线程支持。线程创建,销毁需要事件。如果创建时间+销毁时间>执行事件,就会很亏!

②问:造很多的线程,得需要空间来放它们,会不会造成内存紧张?

答:java对象占用堆内存,操作系统线程占用系统内存,根据jvm规范,一个线程默认最大栈大小1M,这个栈空间是需要系统内存中分配的。线程过多,会消费很多的内存。操作系统需要频繁切换线程上下文(大家都想被运行),影响性能。

g.该如何正确使用多线程?

多线程的目的:充分利用cpu并发做事(多做事)

线程的任务:将代码送给cpu执行 用合适数量的线程不断运送代码即可。

这合适数量的线程就构成了一个池。

有任务要执行,就放入池中,池中的一个线程把任务运送到cpu执行。

h.如何确定合适数量的线程?

1.如果是计算型任务:cpu数量的1-2倍

2.如果是IO型任务: 需要多一些线程,要根据具体的IO阻塞时长进行考量决定。比如tomcat中默认最大线程数为200。也可考虑根据需要在一个最小数量和最大数量间自动增减线程数(cpu核数20-30倍)。

注:当然具体数量请根据应用进行实测,这里只提供估值。

二.简易线程池分析

a.线程池中有什么?

仓库、任务

线程

b.线程池要做哪些事情? 

接受任务放入仓库 

工作线程从仓库取任务、执行 

没有任务时,线程阻塞,当有任务时唤醒线程执行

c.建模

任务用什么表示Runnable

仓库用什么表示

池中线程用什么存放

如果做到工作线程的阻塞、唤醒

d.BlockingQueue介绍 

阻塞队列,线程安全。

在队列为空时的获取阻塞,在队列满时放入阻塞。

BlokingQueue方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同: .第一种是抛出一个异常;第二种是返回一个特殊值(null或false具体操作取决于操作) ;第三种是在操作可以成功前,无限期地阻塞当前线程;第四种是在放弃前只在给定的最大时间限制内阻塞。详情见下表:

e.首先实现一个固定池大小的线程池理论

1.完成池的构成元素初始化。

2.完成提交任务方法。如果仓库满了就返回false。

3.完成线程中取任务、执行。

4.实现关闭功能:关闭后,不能接受新任务,待现有任务都完成后,所有线程都结束。

f.简单实现(为了贴代码美观,把所有的东西都写在了一个类里面)

package threadExercise;

import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;

public class MyFixedSizeThreadPool {
	//仓库
	private BlockingQueue<Runnable> taskQueue;
	
	//工作线程
	private List<Worker> workers;
	
	//线程池的工作标志
	private volatile boolean working = true;
	
	public MyFixedSizeThreadPool(int poolSize , int taskQueuesSize) {
		if(poolSize <= 0 || taskQueuesSize <= 0) {
			throw new IllegalArgumentException("参数错误");
		}
		this.taskQueue = new LinkedBlockingQueue<Runnable>(taskQueuesSize);

		//初始化线程
		this.workers = Collections.synchronizedList(new ArrayList<>());
		for(int i = 0 ; i < poolSize ; i++) {
			Worker w = new Worker(this);
			w.start();
			this.workers.add(w);
		}
	}
	
	//放入任务的方法
	public boolean submit(Runnable task) {
		if(this.working) {
			return	this.taskQueue.offer(task);
		}
		return false;
	}
	
	//关闭方法
	public void shutdown() {
		this.working = false;
		//中断阻塞的线程
		for(Thread t : this.workers) {
			if(t.getState().equals(State.BLOCKED) 
					|| t.getState().equals(State.WAITING)
					|| t.getState().equals(State.TIMED_WAITING)) {
				t.interrupt();
			}
		}
	}
	
	private static class Worker extends Thread {
		private MyFixedSizeThreadPool pool;
		
		public Worker(MyFixedSizeThreadPool pool) {
			super();
			this.pool = pool;
		}
		
		@Override
		public void run() {
			//执行的任务数量计算
			int taskCount = 0;
			
			
			while(this.pool.working || this.pool.taskQueue.size() > 0) {
				Runnable task = null;
			
				try{
				//当队列中有任务,池已经关闭时
					if(this.pool.working) {
						task = this.pool.taskQueue.take();
					} else {
						task = this.pool.taskQueue.poll();
					}
				} catch (Exception e) {
						System.out.println("这里被中断");
				}
				
				if(task != null) {
					task.run();
					taskCount++;
					System.out.println(Thread.currentThread().getName() + "执行完" + "\ttaskCount:" + taskCount);
				}
			}
			Executor e = null;		
			System.out.println("run结束");
		}
	}

	
	
	public static void main(String[] args) {
		MyFixedSizeThreadPool pool = new MyFixedSizeThreadPool(3, 6);
		for(int i = 0 ; i < 6 ; i++) {
			pool.submit(new Runnable() {
				
				@Override
				public void run() {
					System.out.println("task begin!");
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						System.out.println("睡眠睡眠");
					}
					System.out.println("task end!");
				}
			});
		}
		pool.shutdown();
		System.out.println("结束");
	}
}

三.java并发包的线程池超级简的介

重要的类关系如下(这是一个关系):

I:Executor                         void execute(Runnable command);

    I: ExecutorService           加入Callable、Future、关闭方法

        C:ForkJoinPool         支持forkJoin框架的线程池实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值