文章目录
多线程基础
1. Thread名称
Thread默认有一个名称, 以Thread-开头,从0开始计数。
2. Thread中若没有传递runnable实例。同样可以运行。
3. Thread Group
若创建线程的时候,没有指定ThreadGroup则使用的是父线程的ThreadGroup。两者线程会在同一个ThreadGroup中。
4. StackSize
- 此为Thread的构造函数参数,表示此线程可以使用的栈大小,而不是使用JVM默认分配的大小。若是没有指定此参数,则默认为0,代表忽略此参数,该参数会被JNI调用。
- 此参数在有的平台生效,有的平台不会生效。
5. Daemon
当父线程结束,此线程也会结束,不会挂在后台一直执行。 Daemon必须放在start之后执行,否则报错异常。
6. Join
只针对 join之后的线程,必须得等join之前的线程执行完成,才能往下面执行。join可以设置衣蛾timeOut,表示join多久,超过此时间段,则接着往下面执行代码。 join必须放在start之后,才能起效;但是,放start之前也不会报错。
7. Interrupt
当调用Interrupt方法的时候,若在线程中使用了sleep, wait,join这些方法,会导致线程抛出中断异常,关闭线程。 interrupt是中断被join的那个线程。
8. 关闭一个Thread(Grace For Close Thread)
- 原来的jdk中使用的是stop方法来关闭一个线程,后来因为此方法关闭线程会产生一系列问题。因此,此方法不再推荐使用。
- 解决方法:
1. 使用Volatile修饰的一个boolean值,使用while监控此线程,什么时候推出程序。 使用volatile的原因。因为,普通的属性是在每个线程中单独存在各自的副本,修改不糊影响到其它线程中。而Volatile则强制要求线程更新了数据,其它线程需要重新load数据。保证数据的正确性。
public class ThreadInterruptDemo {
private static class Worker extends Thread {
private volatile boolean is_Down = false;
@Override
public void run() {
while (is_Down) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void shutDown() {
this.is_Down = true;
}
}
public static void main(String[] args) throws InterruptedException {
Worker worker = new Worker();
worker.start();
Thread.sleep(10_000);
worker.shutDown();
}
}
- 使用中断(Interrupt)机制来退出线程:调用线程的Interrupt方法,然后,在方法中再次调用线程的sleep, join, wait方法,可以导致线程抛出中断异常,从而导致线程的退出。
public class ThreadInterruptDemo2 {
private static class Worker extends Thread {
@Override
public void run() {
while (true) {
if (Thread.interrupted()) { // 若中断, 则退出线程.
return;
}
System.out.println("ing.........");
}
}
}
public static void main(String[] args) throws InterruptedException {
Worker worker = new Worker();
worker.start();
Thread.sleep(3_000);
worker.interrupt();
}
}
9. 强制关闭一个线程(Force close Thread)
不推荐使用stop方法。而可以使用守护线程的方法,关闭主要线程,从而导致执行任务的守护线程的退出。
public class ThreadService {
private Thread executeThread;
private boolean finished = false;
public void execute(Runnable task) { executeThread = new Thread(() -> {
Thread runner = new Thread(task); //真正执行任务的线程.
runner.setDaemon(true); // 设置为守护线程, 则只需要主线程退出, 守护线程也就退出了.
runner.start();
try { runner.join(); // 拦截代码往下面执行.等待任务执行完成.
finished = true;
} catch (InterruptedException e) { System.out.println("触发中断异常");
} });
executeThread.start();
}
/**
* 外部其它线程, 调用此方法关闭executeThread,
* 从而保证了可以强制关闭runner(执行任务线程)的关闭.
* @param maxSpendTime: 此任务最大可以消耗的时间, 超时则关闭此任务.
*/
public void shutDown(long maxSpendTime) { long currentTimeMillis = System.currentTimeMillis();
while (!finished) { long endTime = System.currentTimeMillis();
if ((endTime - currentTimeMillis) >= maxSpendTime) { System.out.println("此任务超时....");
executeThread.interrupt(); //使用了join, 产生中断异常.
break;
}
try {
executeThread.sleep(1);
} catch (InterruptedException e) { System.out.println("执行线程被中断");
break;
} }
finished = false;
}}
public class CloseThreadMain {
public static void main(String[] args) {
ThreadService service = new ThreadService();
long currentTimeMillis = System.currentTimeMillis();
service.execute(() -> { // 执行一个长时间任务.
while (true) { // 触发中断异常
}
/*try { // 正常任务执行结束.
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
});
service.shutDown(10000); //制定超过多少时间, 关闭此线程.
long endTime = System.currentTimeMillis();
System.out.println(endTime - currentTimeMillis); // 得到线程花费时间.
}}