Thread(ThreadGroup group,Runnable target)
:group属于的线程组,target为新线程Thread(ThreadGroup group,Runnable target,String name)
:group属于的线程组,target为新线程,name:线程名Thread(ThreadGroup group,String name)
:新线程名为name,属于group线程组(1)构造方法
ThreadGroup(String name)
:以指定线程组名字来创建新线程组ThreadGroup(ThreadGroup parent,String name)
:以指定的名字、指定的父线程组来创建一个新线程组。(2)常用操作方法
int activeCount()
:获取线程组中活动线程的数量interrupt()
:中断线程组中所有线程isDaemon()
:是否为后台线程组setDaemon(boolean daemon)
:设置为后台线程组setMaxPriority(int pri)
:设置线程组的最高优先级package com.jtzen9;
public class Main {
public static void main(String[] args) {
// 获取主线程所在的线程组,这是所有线程默认的线程组
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("主线程组的名字:" + mainGroup.getName());
System.out.println("主线程组是否是后台线程组:" + mainGroup.isDaemon());
new MyThread("主线程组的线程").start();
ThreadGroup tg = new ThreadGroup("新线程组");
tg.setDaemon(true);
System.out.println("tg线程组是否是后台线程组:" + tg.isDaemon());
MyThread tt = new MyThread(tg , "tg组的线程甲");
tt.start();
new MyThread(tg , "tg组的线程乙").start();
}
}
class MyThread extends Thread {
// 提供指定线程名的构造器
public MyThread(String name) {
super(name);
}
// 提供指定线程名、线程组的构造器
public MyThread(ThreadGroup group , String name) {
super(group, name);
}
public void run() {
for (int i = 0; i < 20 ; i++ ) {
System.out.println(getName() + " 线程的i变量" + i);
}
}
}
输出结果:
主线程组的名字:main
主线程组是否是后台线程组:false
tg线程组是否是后台线程组:true
主线程组的线程 线程的i变量0
主线程组的线程 线程的i变量1
主线程组的线程 线程的i变量2
主线程组的线程 线程的i变量3
主线程组的线程 线程的i变量4
tg组的线程甲 线程的i变量0
tg组的线程甲 线程的i变量1
tg组的线程甲 线程的i变量2
tg组的线程甲 线程的i变量3
tg组的线程甲 线程的i变量4
tg组的线程乙 线程的i变量0
tg组的线程乙 线程的i变量1
tg组的线程乙 线程的i变量2
tg组的线程乙 线程的i变量3
tg组的线程乙 线程的i变量4
ThreadGroup内定义了一个方法:void uncaughtException(Thread t,Throwable e)
,该方法可以处理该线程组内的任意线程所抛出的未处理异常。
ThreadGroup类实现了Thread.UncaughtExceptionHandler
接口,所以每个线程所属的线程组将会作为默认的异常处理器。当一个线程抛出未处理异常时,JVM会首先查找该异常对应的异常处理器处理该异常;否则,JVM将会调用该线程所属的线程组对象的uncaughtException()
方法来处理该异常。
例子:
package com.jtzen9;
public class Main {
public static void main(String[] args) {
// 设置主线程的异常处理器
Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler());
int a = 5 / 0;
System.out.println("程序正常结束!");
}
}
// 定义自己的异常处理器
class MyExHandler implements Thread.UncaughtExceptionHandler {
// 实现uncaughtException方法,该方法将处理线程的未处理异常
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t + " 线程出现了异常:" + e);
}
}
输出:
Thread[main,5,main] 线程出现了异常:java.lang.ArithmeticException: / by zero
与数据库连接池类似,线程池在系统启动时即创建大量空闲的线程,程序将一个Runnable对象或Callable对象传给线程池,线程池就会启动一个线程来执行它们的run()或call()方法,当执行完毕后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
Executors
工厂类:该工厂类包含多个静态工厂方法来创建线程池。 ExecutorService
类:代表尽执行线程的线程池,即只要线程池中有空闲线程,就立即执行线程任务ScheduledExecutorService
类:代表可在指定延迟后或周期性地执行线程任务的线程池。使用线程池来执行线程任务的步骤如下:
例子:
package com.jtzen9;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws Exception{
// 创建一个具有固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(6);
// 使用Lambda表达式创建Runnable对象
Runnable target = () ->{
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "的i值为:" + i);
}
};
// 向线程池中提交两个线程
pool.submit(target);
pool.submit(target);
// 关闭线程池
pool.shutdown();
}
}
输出:
pool-1-thread-1的i值为:0
pool-1-thread-2的i值为:0
pool-1-thread-1的i值为:1
pool-1-thread-2的i值为:1
pool-1-thread-1的i值为:2
pool-1-thread-2的i值为:2
pool-1-thread-1的i值为:3
pool-1-thread-2的i值为:3
pool-1-thread-1的i值为:4
pool-1-thread-2的i值为:4
pool-1-thread-1的i值为:5
pool-1-thread-2的i值为:5
pool-1-thread-1的i值为:6
pool-1-thread-1的i值为:7
pool-1-thread-1的i值为:8
pool-1-thread-2的i值为:6
pool-1-thread-1的i值为:9
pool-1-thread-2的i值为:7
pool-1-thread-2的i值为:8
pool-1-thread-2的i值为:9
为了充分利用多CPU、多核CPU的优势,可以考虑把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来即可
ForkJoinPool
类支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结果。
ForkJoinPool是ExecutorService
的实现类,因此是一种特殊的线程池。创建了ForkJoinPool类实例,就可以调用ForkJoinPool的submit(ForkJoinTask task)
或invoke(ForkJoinTask task)
方法来执行指定任务。其中ForkJoinTask代表一个可以并行、合并的任务。
ForkJoinTask是一个抽象类,有两个抽象子类:RecursiveAction
(代表没有返回值的任务)和RecursiveTask
(代表有返回值的任务)。
package com.jtzen9;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
public class Main {
public static void main(String[] args) throws Exception{
int[] arr = new int[100];
Random rand = new Random();
int total = 0;
// 初始化100个数字元素
for (int i = 0 , len = arr.length; i < len ; i++ )
{
int tmp = rand.nextInt(20);
// 对数组元素赋值,并将数组元素的值添加到sum总和中。
total += (arr[i] = tmp);
}
System.out.println(total);
// 创建一个通用池
ForkJoinPool pool = ForkJoinPool.commonPool();
// 提交可分解的CalTask任务
Future future = pool.submit(new CalTask(arr , 0 , arr.length));
System.out.println(future.get());
// 关闭线程池
pool.shutdown();
}
}
// 继承RecursiveTask来实现"可分解"的任务
class CalTask extends RecursiveTask {
// 每个“小任务”只最多只累加20个数
private static final int THRESHOLD = 20;
private int arr[];
private int start;
private int end;
// 累加从start到end的数组元素
public CalTask(int[] arr , int start, int end) {
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
// 当end与start之间的差小于THRESHOLD时,开始进行实际累加
if(end - start < THRESHOLD) {
for (int i = start ; i < end ; i++ ) {
sum += arr[i];
}
return sum;
}
else {
// 如果当end与start之间的差大于THRESHOLD时,即要累加的数超过20个时
// 将大任务分解成两个小任务。
int middle = (start + end) / 2;
CalTask left = new CalTask(arr , start, middle);
CalTask right = new CalTask(arr , middle, end);
// 并行执行两个“小任务”
left.fork();
right.fork();
// 把两个“小任务”累加的结果合并起来
return left.join() + right.join(); // ①
}
}
}
942
942
package com.jtzen9;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws Exception{
ForkJoinPool pool = new ForkJoinPool();
// 提交可分解的PrintTask任务
pool.submit(new PrintTask(0 , 300));
pool.awaitTermination(2, TimeUnit.SECONDS);
// 关闭线程池
pool.shutdown();
}
}
// 继承RecursiveAction来实现"可分解"的任务
class PrintTask extends RecursiveAction {
// 每个“小任务”只最多只打印50个数
private static final int THRESHOLD = 50;
private int start;
private int end;
// 打印从start到end的任务
public PrintTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected void compute() {
// 当end与start之间的差小于THRESHOLD时,开始打印
if(end - start < THRESHOLD) {
for (int i = start ; i < end ; i++ ) {
System.out.println(Thread.currentThread().getName()
+ "的i值:" + i);
}
}
else {
// 如果当end与start之间的差大于THRESHOLD时,即要打印的数超过50个
// 将大任务分解成两个小任务。
int middle = (start + end) / 2;
PrintTask left = new PrintTask(start, middle);
PrintTask right = new PrintTask(middle, end);
// 并行执行两个“小任务”
left.fork();
right.fork();
}
}
}
部分输出:
ForkJoinPool-1-worker-1的i值:262
ForkJoinPool-1-worker-1的i值:263
ForkJoinPool-1-worker-1的i值:264
ForkJoinPool-1-worker-1的i值:265
ForkJoinPool-1-worker-1的i值:266
ForkJoinPool-1-worker-2的i值:112
ForkJoinPool-1-worker-2的i值:113
ForkJoinPool-1-worker-2的i值:114
ForkJoinPool-1-worker-3的i值:37
ForkJoinPool-1-worker-1的i值:267
ForkJoinPool-1-worker-3的i值:42
ForkJoinPool-1-worker-2的i值:120
ForkJoinPool-1-worker-3的i值:43
ForkJoinPool-1-worker-0的i值:75
ForkJoinPool-1-worker-2的i值:121
ForkJoinPool-1-worker-0的i值:76
ForkJoinPool-1-worker-1的i值:268
ForkJoinPool-1-worker-3的i值:44
ForkJoinPool-1-worker-1的i值:269
ForkJoinPool-1-worker-0的i值:77
ForkJoinPool-1-worker-2的i值:122
ForkJoinPool-1-worker-0的i值:78
ForkJoinPool-1-worker-0的i值:79
ForkJoinPool-1-worker-0的i值:80
ForkJoinPool-1-worker-0的i值:81
ForkJoinPool-1-worker-0的i值:82
ForkJoinPool-1-worker-0的i值:83
ForkJoinPool-1-worker-0的i值:84
ForkJoinPool-1-worker-0的i值:85
ForkJoinPool-1-worker-0的i值:86
ForkJoinPool-1-worker-0的i值:87
ForkJoinPool-1-worker-0的i值:88
ForkJoinPool-1-worker-1的i值:270
ForkJoinPool-1-worker-3的i值:45
ForkJoinPool-1-worker-1的i值:271
ForkJoinPool-1-worker-0的i值:89
ForkJoinPool-1-worker-2的i值:123
ForkJoinPool-1-worker-0的i值:90
ForkJoinPool-1-worker-1的i值:272
ForkJoinPool-1-worker-3的i值:46
ForkJoinPool-1-worker-1的i值:273
ForkJoinPool-1-worker-0的i值:91
ForkJoinPool-1-worker-2的i值:124
ForkJoinPool-1-worker-0的i值:92