1 分析线程的工具
1.1 visualVM
JDK自带,监控工具在bin/jvisualvm.exe,能监控线程,内存情况,查看方法的CPU时间和内存中的对象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。
自动显示当前本机所运行的Java程序,还可添加远程的Java VM。
2 停止线程
2.1 stop() 已过期
public class StopThread1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
int count = 0;
System.out.println("线程开始....");
for (int i = 0; i < 20; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) { // stop()方法不会抛出这个错
throw new RuntimeException(e);
}
count++;
}
System.out.println("线程结束....count:" + count);
});
thread.start();
TimeUnit.SECONDS.sleep(5);
thread.stop(); //线程中会抛出ThreadDeath错误
}
}
图 stop停止线程方法运行结果
stop()方法:强制线程停止执行。不能确定线程在哪里被停止了。
2.2 interrupt()
public class StopThread2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
int count = 0;
try {
System.out.println("线程开始....");
for (int i = 0; i < 20; i++) {
TimeUnit.SECONDS.sleep(1);
count++;
}
} catch (InterruptedException e) {
System.out.println("线程结束....count:" + count);
}
});
thread.start();
TimeUnit.SECONDS.sleep(5);
thread.interrupt();
}
}
图 interrupt停止线程运行结果
interrupt()中断线程,在线程中通过异常法来停止线程,能确定线程在哪里被停止及可以及时处理任务。
2.2.1 interrupted() 与 isInterrupted()
1) public static boolean interrupted(): 测试currentThread() 是否已经中断。当前线程是指执行this.interrupted()方法的线程。
2)public boolean this.isInterrupted():测试this关键字所在线程类的对象是否已经中断。
图 interrupted方法源码
执行interrupted()方法后,中断标志会被清除(线程状态从中断恢复成正常)。
3 暂停线程
3.1 suspend() 已过期
public class SuspendThread {
private static class SyncService {
public void show() {
System.out.println("thread:" + Thread.currentThread().getName());
Thread.currentThread().suspend();
}
}
public static void main(String[] args) throws InterruptedException {
SyncService syncService = new SyncService();
Thread thread1 = new Thread(() -> {
syncService.show();
});
thread1.setName("thread1");
thread1.start();
thread1.resume(); //该操作可能会早于show()方法里面的suspend操作
}
}
图 线程一直被挂起
3.2 LockSupport
public class LockSupportThread {
private static class SyncService {
public void show() throws InterruptedException {
System.out.println("thread:" + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
LockSupport.park();
}
}
public static void main(String[] args) throws InterruptedException {
SyncService syncService = new SyncService();
Thread thread1 = new Thread(() -> {
try {
syncService.show();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread1.setName("thread1");
thread1.start();
LockSupport.unpark(thread1); //该操作早于show()方法里面的park操作
}
}
图 线程正常结束
即使unpack()操作发生在pack()之前,它也可以使下一次的pack()操作立即返回。
另外,suspend()执行的线程状态为运行状态,pack()执行的线程状态为等待。
图 绿色代表运行,黄色代表等待
4 线程优先级
Java中线程的优先级分为10个等级,即1~10。
4.1 优先级的三个特性
1) 可继承性:比如A线程启动B线程,则B线程的优先级与A是一样的。
2)规律性:CPU会尽量将执行资源让给优先级较高的线程。
3)随机性:优先级较高的线程不一定每次都先执行完。
5 守护线程
Java中有两种线程,一种是用户线程,也称非守护线程;另一种是守护线程。
守护线程是一种特殊的线程,当进程中不存在非守护线程时,则守护线程自动销毁。典型的守护线程就是垃圾回收线程。
主线程main也属于用户线程。凡是调用setDaemon(true)的线程才是守护线程。
public class DaemonThread {
private static class MyThread extends Thread {
@Override
public void run() {
try {
System.out.println("守护线程开始");
TimeUnit.SECONDS.sleep(50);
System.out.println("守护线程结束");
} catch (InterruptedException e) {
System.out.println("守护线程被终止");
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();
TimeUnit.SECONDS.sleep(2);
System.out.println("main线程执行完毕");
}
}
图 守护线程执行结果
6 并发与并行
并发是逻辑上的同时存在,而并行是物理上的同时存在。
并发是指多线程逻辑上,在同一时间执行。但是实际在CPU上每个线程分配了时间片,线程按顺序执行。
并行是多核CPU,两个线程分别在不同CPU上同一时间执行。