- #Java多线程基础
@基于Runnable接口、Thread类的多线程
--->Demo样例
import static java.lang.System.in;
import static java.lang.System.out;
import java.util.Scanner;
import java.text.DecimalFormat;
public class Temp{
public static void main(String... args) throws InterruptedException{
//通过Thread调用实现了runnable接口的类所生产的实例
Runnable runnerA = new Runnable(){
public void run(){
int i=10;
while(i-->0){
out.println("runnerA's step:"+i+"\t#"+Thread.currentThread().getState());
}
}
};
Thread threadA = new Thread(runnerA);
//直接继承Thread类
Thread threadB = new Thread(){
public void run(){
int i=200;
while(i-->0){
out.println("runnerB's step:"+i);
out.println("threadB中观察threadA的状态为:"+threadA.getState());
}
}
};
//类似于直接继承Thread类,但方式是通过lambda表达式来设计
new Thread(()->{
int i=20;
while(i-->0) out.println("runnerC's step:"+i);
}).start();
out.println("启动threadA前:"+threadA.getState());
threadA.start();
out.println("启动threadA后:"+threadA.getState());
threadB.setDaemon(true);
threadB.start();
//Thread.sleep(100);
}
}
@普通线程与Daemon线程
在多线程的应用中,JVM会在所有非Daemon线程结束之后中止。Daemon线程一般用作为服务线程,常见的如JVM中的GC线程就是一个Daemon线程。普通线程(Thread类)可以通过setDaemon()方法设置为Daemon线程。(必须在执行start()调用前设置才有效)
@线程的基本状态
通过Thread的getState()调用可以获取到线程的基本状态(6种)如下:
1.NEW
尚未启动的线程处于此状态。
2.RUNNABLE
在Java虚拟机中执行的线程处于此状态。
3.BLOCKED
被阻塞等待监视器锁定的线程处于此状态。
4.WAITING
正在等待另一个线程执行特定动作的线程处于此状态。
5.TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
6.TERMINATED
已退出的线程处于此状态。
@设置线程的优先权
通过Thread的setPriority()设置线程的优先级,优先级的范围必须大于等于Thread.MIN_PRIORITY(1),小于等于Thread.MAX_PRIORITY(10),默认是Thread.NORM_PRIORITY(5),不在范围内会抛出异常。线程的优先级越高,相同条件下有限被排入CPU。
@中止线程的blocked状态
通过其它线程调用对应线程的interrupt()方法,可以使对应的线程从blocked状态退出来,但对应线程会抛出IterruptedException。
--->Demo样例
import static java.lang.System.in;
import static java.lang.System.out;
import java.util.Scanner;
import java.text.DecimalFormat;
public class Temp{
public static void main(String... args) throws InterruptedException{
Thread tA = new Thread(()->{
out.println("tA is running...");
try{
while(true){
Thread.sleep(5000);
out.println("...");
}
}catch(InterruptedException e){
out.println("tA catch ExceptionMsg:"+e.toString());
}
out.println("tA is over");
});
Scanner scan = new Scanner(in);
tA.start();
out.println("now, input something and pass 'enter'");
scan.next();
tA.interrupt();
out.println("main is over");
}
}
@安插线程
当前线程正在运行时,可以通过join()方法安插其它线程进来,等安插的线程完成后再继续运行之前的线程。join()方法也可以指定安插线程的最大运行时间,到了最大时间会强行结束安插线程。
--->Demo样例
import static java.lang.System.in;
import static java.lang.System.out;
import java.util.Scanner;
import java.text.DecimalFormat;
public class Temp{
public static void main(String... args) throws InterruptedException{
Thread tA = new Thread(()->{
out.println("tA is running...");
int i=10;
while(i-->0) out.println("subThread ...");
out.println("tA is over");
});
out.println("main is start...");
tA.start();
tA.join();
int i=20;
while(i-->0) out.println("main ...");
//tA.start(); //运行结束后,不允许再次调用start方法,否则会抛出IllegalThreadStateException
out.println("main is over");
}
}
@停止线程
线程运行结束后,进入TERMINATED 状态,这时不允许再次调用start()方法,否则会抛出IllegalThreadStateException。
线程的结束,应该设计合理的运行流程,让其自行结束。或者通过设计特殊参数,使得线程在参数变更后自行结束。
(注释有@Deprecated的stop方法不推荐使用,因为其已经被定义为过时的)
- #线程组
每个线程都有所属的一个线程组(ThreadGroup)。在创建一个线程时,若没有指定其所属的线程组,则默认是属于当前创建其的线程所属的线程组。
获取当前线程所属的线程组:
Thread.currentThread().getThreadGroup().getName();
需要注意的是,线程的线程组一旦指定就无法更改。
@创建线程组
指定线程组名称:
ThreadGroup group1 = new ThreadGroup("group1");
指定线程组名称及其父线程组:
ThreadGroup group2 = new ThreadGroup(group1, "group2");
@线程组的作用
线程组的一些方法可以对群组内的所有线程产生作用。
例如:
interrupt():可以中断群组中所有的线程;
setMaxPriority():设定群组中所有线程的最大优先权(本来就有更高优先权的线程不受影响);
@常见方法的使用
activeCount():获取当前群组中所有线程的数量;
enumerate():传入一个Thread数组,将群组中的所有线程复制到数组中;
uncaughtException():群组中某个线程发生异常而未捕获时,JVM会调用其所属群组中的这个方法。
--->通过Thread的setUncaughtExceptionHandler()设置未捕获异常的处理调用,Demo举例
import static java.lang.System.in;
import static java.lang.System.out;
import java.util.Scanner;
import java.text.DecimalFormat;
public class Temp{
public static void main(String... args) throws InterruptedException{
ThreadGroup group = new ThreadGroup("groupTest");
Thread thread1 = new Thread(group, ()->{
throw new RuntimeException("thread--1(通过setUncaughtExceptionHandler设置了异常处理方式) 运行时异常测试");
});
thread1.setUncaughtExceptionHandler((thread, throwable)->{
out.println(thread.getName()+"--->"+ throwable.getMessage());
});
new Thread(group, ()->{
throw new RuntimeException("thread--2 运行时异常测试");
}).start();
thread1.start();
}
}
@线程未捕获异常调用的流程
未捕获异常会由线程实例setUncaughtExceptionHandler()设定的Thread.UncaughtExceptionHandler实例处理,之后是线程的ThreadGroup,然后才是默认的Thread.UncaughtExceptionHandler。