【java多线程】守护线程、线程停止、volatile的深入了解
文章目录
线程的优雅停止
在多线程的操作之中如果要启动多线程肯定使用的Thread类中的start()方法,而对于咱们的多线程需要进行停止处理,原来的Thread类提供有stop()方法,但是对于这些方法从JDK1.2版本就已经将其废除了,而且一直到现在也不建议出现在你的代码中,而除了stop()之外还有几个方法也别禁用了:
-
停止多线程:
public void stop();
-
销毁多线程:
public void destory();
-
挂起线程:
public final void suspend();、暂停执行
-
恢复挂起的线程执行:
public final void resume();
之所以废除掉这些方法,主要原因是因为这些方法有可能导致线程的死锁,所以JDK1.2开始就都不建议使用了。如果这个时候要想实现线程的停止,需要通过一种柔和的方式来进行。
范例:
public class ThreadD {
public static boolean flag = true;
public static void main(String[] args) throws InterruptedException {
new Thread(( ) -> {
long num = 0;
while(flag){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行 +" + num ++);
}
},"执行线程").start();
Thread.sleep(200);
flag = false;
}
}
万一现在有其它线程去控制这个flag的内容,那么这个时候对于线程的停止也不是说停止就立刻停止的,而是会在执行中判断flag的内容来完成。
守护线程
现在假设有一个人并且这个人有一个保镖,那么这个保镖一定是这个人活着的时候进行保护,如果这个人死了就没用了。所以在多线程里面可以进行守护线程的定义,也就是说如果现在主线程的程序或者其它的线程还在执行的时候,守护线程将一直存在,并且运行在后台的状态。
在Thread类中提供有如下的守护线程的操作方法:
-
设置守护线程:
public final void setDaemon(boolean on);
-
判断是否为守护线程:
public final Boolean isDaemon();
范例:使用守护线程
public class ThreadD {
public static void main(String[] args) throws InterruptedException {
Thread userThread = new Thread(( ) -> {
for(int x = 0 ; x < 10 ; x ++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行 x = " + x);
}
},"用户线程");
Thread daemonThread = new Thread(( ) -> {
for(int x = 0 ; x < Integer.MAX_VALUE ; x ++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在执行 x = " + x);
}
},"守护线程");
daemonThread.setDaemon(true); //设置为守护线程
userThread.start();
daemonThread.start();
}
}
可以发现所有的守护线程是围绕在用户线程周围,如果程序执行完毕了,守护线程也就消失了。而在JVM找那个最大的守护线程就是GC线程。
程序执行中GC线程会一直存在,如果程序执行完毕,那么GC线程也将消失。
volatile关键字
在多线程的定义之中,volatile是在属性定义上使用的,表示此属性为直接数据操作,而不进行副本的拷贝处理,这样的话在一些书上就将其错误的理解为同步属性了。
在正常进行变量处理的时候往往会经历如下几个步骤:
- 获取变量原有的数据内容副本;
- 利用副本为变量进行数学计算;
- 将计算后的变量,保存到原始空间之中;
而如果一个属性追加了volatile关键字,表示的就是不使用副本,而是直接操作原始变量,相当于节约了:拷贝副本、重新保存的步骤。
流程图如下:
面试题:请解释volatile与synchronized的区别?
- volatile主要的属性上使用,而synchronized是在代码块与方法上使用的;
- volatile无法描述同步的处理,它只是一种直接内存的处理,避免了副本的操作,而synchronized是实现同步的。