线程组 线程组的作用是:可以批量管理线程或线程组对象,有效地对线程或线程组对象进行组织。 构造函数
//注意:Main线程的ThreadGroup的名字是main,Main线程的名字也是main,Main线程是由jvm创建 ThreadGroup(String name)//默认parent为当前线程组 ThreadGroup(ThreadGroup parent, String name)将某一个线程放入线程组:
public class ThreadGroupCreat { public static void main(String[] args) { ThreadGroup tg1=new ThreadGroup("TG1"); Thread t1=new Thread(tg1,"t1"){ public void run(){ while(true){ try { System.out.println(getThreadGroup().getName()); System.out.println(getThreadGroup().getParent()); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }; t1.start(); } }运行结果:
TG1//线程组名 java.lang.ThreadGroup[name=main,maxpri=10] //父线程和优先级 TG1 java.lang.ThreadGroup[name=main,maxpri=10]具体方法
//评估当前活跃的线程数,包括当前group和子group //不准确因为有可能刚好有新线程加入或销毁 activeCount() //返回当前活跃的子线程组 activeGroupCount() //评估当前线程是否有权限改变这个线程组 checkAccess() //用于销毁线程组及其所有子组。 线程组必须为空,表示线程组中的所有线程都已停止,否则会抛出异常 //它不能作为线程退出的方法 destroy() //复制当前线程组包括子组的线程到数组中,如果recurse=false,则不复制子组 enumerate(Thread[] list) enumerate(Thread[] list, boolean recurse) //返回当前线程组名字 getName() //获得父线程组 getParent() //打断线程组中所有线程 interrupt() //等线程组中所有线程运行完成后该线程组会自动销毁,不需要手动调用destroy() setDaemon(boolean daemon) //标志位判断函数 isDaemon() isDestroyed() parentOf(ThreadGroup g)线程池 线程的创建和销毁需要消耗资源,所以通过线程池,用完的线程可以及时回收供其他程序使用,节约了创建和销毁的浪费。 例子:在Tomcat服务器启动时创建线程池用来处理请求。
线程池的初始化
初始化一定数量线程,进入阻塞状态,等待任务。通过线程队列管理启动线程池自身监控线程任务调度
任务放入任务队列,并通知线程开始取任务工作任务队列的放入和取出需要加锁拒绝策略
当任务队列过长时,可以做出选择,抛出异常;直接丢弃;阻塞;临时队列闲时回收和忙时扩增
init–初始大小,active–活跃大小,max–最大线程数通过启动线程池的一个监控程序,实时对线程队列进行扩增或缩小线程关闭
run状态下,通过标志位改变使线程结束block状态下,通过interrupt让线程捕获异常使线程结束简单线程池源码:
package com.chao.concurrency_basic.chapter13_SIMPLE_THREAD_POOL; import java.util.ArrayList; import java.util.LinkedList; /** * 实现了简单的线程池的创建、任务队列、 * 维护线程池中线程的状态、线程接受任务并执行 */ public class SimpleThreadPool { // 线程池默认大小为10 private static final int DEFAULT_SIZE = 10; private int size; // 任务队列 private static final LinkedList<Runnable> TASK_QUEUE = new LinkedList<>(); private static final String PREFIX = "Simple-thread-"; // 线程队列 private static final ArrayList<Thread> THREAD_QUEUE = new ArrayList<>(); // 将线程池中的所有线程归于一个线程组 private static final ThreadGroup THREAD_GROUP = new ThreadGroup("Simple-ThreadGroup"); private static volatile int seq = 0; public SimpleThreadPool(){ this(DEFAULT_SIZE); } public SimpleThreadPool(int size){ this.size = size; init(); } private void init(){ for(int i = 0; i<size; i++){ createWorkThread(); } } private void createWorkThread(){ WorkThread t = new WorkThread(THREAD_GROUP,PREFIX + (++seq)); t.start(); THREAD_QUEUE.add(t); } public void submit(Runnable runnable){ synchronized (TASK_QUEUE){ TASK_QUEUE.addLast(runnable); // 任务加入后,通知处于等待中的线程 TASK_QUEUE.notifyAll(); } } private enum TaskState{ FREE,RUNNING, BLOCKED,DEAD } private class WorkThread extends Thread{ private TaskState taskState = TaskState.FREE; WorkThread(ThreadGroup g, String name){ super(g,name); } /** * 线程状态为非DEAD状态时,检测任务队列中是否有任务,有则开始接任务 * 当其他线程正在取任务时,其他线程等待(状态为阻塞状态) * 从任务队列中取走任务(状态变为运行中),然后开始做任务 * 做完任务后(状态变为自由状态,等待下一个任务) * 线程不结束,回到线程池中 */ public void run(){ OUTER: while (this.taskState != TaskState.DEAD){ Runnable runnable = null; synchronized (TASK_QUEUE){ while (TASK_QUEUE.isEmpty()){ try { this.taskState = TaskState.BLOCKED; TASK_QUEUE.wait(); } catch (InterruptedException e) { // 当线程任务时被打断,回到线程池重新接任务 this.taskState = TaskState.FREE; break OUTER; } // 被唤醒之后检测到任务队列非空则退出循环接任务 } // 拿到任务 runnable = TASK_QUEUE.removeFirst(); } // 执行任务,放在synchronized外, // 让线程执行任务的同时释放锁,让其他线程可以接任务 if(runnable != null){ this.taskState = TaskState.RUNNING; runnable.run(); this.taskState = TaskState.FREE; } } } private void close(){ this.taskState = TaskState.DEAD; } private TaskState getTaskState() { return taskState; } } public static void main(String[] args) { SimpleThreadPool simpleThreadPool = new SimpleThreadPool(); IntStream.range(0,20) .forEach(i->simpleThreadPool.submit(()->{ Optional.of("The task " + i + " is served by " + Thread.currentThread().getName() + " and start.") .ifPresent(System.out::println); try { Thread.sleep(1_000); } catch (InterruptedException e) { e.printStackTrace(); } Optional.of("The task " + i + " is served by " + Thread.currentThread().getName() + " and finished.") .ifPresent(System.out::println); })); } }