优雅的停止线程
在多线程的操作之中如果要启动多线程肯定使用的是Thread类中start()方法,而如果对于多线程需要进行停止处理,Thread类原本提供有stop()方法,但是对于这些方法从JDK1.2版本开始已经将其废除了,而且一直到现在也不再建议出现在你的代码之中,而除了stop()方法之外还有几个方法也禁用了:
‒ 停止多线程:
@Deprecated(since=“1.2”)
public final void stop()
‒ 销毁多线程: @Deprecated(since=“1.5”,forRemoval=true)
public void destroy()
‒ 挂起线程:
@Deprecated(since=“1.2”)
public final void suspend() // 暂停执行
‒ 恢复挂起线程执行:
@Deprecated(since=“1.2”)
public final void resume()
之所以废除掉这些方法,主要的原因是因为这些方法有可能导致线程的死锁,所以从JDK1.2开始都不建议使用了。如果这个时候要想实现线程的停止需要通过一种柔和的方式来进行
范例:实现线程柔和的停止
public class ThreadDemo{
static boolean flag = true ;
public static void main(String args[]){
new Thread(()->{
long num = 0;
while(flag){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "正在运行\tnum = "+ num++);
}
},"执行线程").start();
try {
Thread.sleep(200);// 运行200毫秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
flag = false ;//停止线程
}
}
万一现在有其他的线程去控制这个flag的内容,那么这个时候对于线程的停止不是说停就停的,而是会在执行中判断flag的内容来完成
后台守护进程
现在假设有一个人并且这个人有一个保镖,那么这个保镖一定是在这个人活着的时候进行守护,如果这个人已经死了,保镖没用了。所以在多线程里面可以进行守护线程的定义,也就是说如果现在主线程的程序或者其他的线程还在执行的时候,那么守护线程将一直存在,并且运行在后台状态
在Thread类里面提供有如下的守护线程的操作方法:
‒ 设置为守护线程:public final void setDaemon(boolean on)
‒ 判断是否为守护线程:public final boolean isDaemon()
import static java.lang.Integer.MAX_VALUE;
public class ThreadDemo{
public static void main(String args[]){
Thread userThread = new Thread(()->{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int x = 0;x < 10; x ++){
System.out.println(Thread.currentThread().getName() + "正在运行\tx = " + x);
}
},"用户线程"); // 完成核心的业务
Thread deamonThread = new Thread(()->{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int x = 0;x < MAX_VALUE ; x ++){
System.out.println(Thread.currentThread().getName() + "正在运行\tx = "+ x);
}
},"守护线程"); // 完成核心的业务
deamonThread.setDaemo(true); // 设为守护线程
userThread.start();
deamonThread.start();
}
}
可以发现所有的守护线程都是围绕在用户线程周围,如果程序执行完毕了,守护线程也就消失了,在整个JVM里面最大的守护线程就是GC线程
程序执行中GC线程会一直存在,如果程序执行完毕,GC线程也将消失.
volatile关键字
在多线程的定义之中,volatile关键字主要是在属性定义上使用的,表示此属性为直接数据操作,而不进行副本的拷贝处理,这样的话在一些书上就将其错误的理解为同步属性了。
在正常进行变量处理的时候往往会经历如下几个步骤:
‒ 获取变量原有的数据内容副本
‒ 为变量进行数学计算
‒ 将计算后的变量,保存到原始空间之中
而如果一个属性上追加了volatile关键字,表示的就是不使用副本,而是直接操作原始变量,相当于节约了:拷贝副本,重新保存的步骤
volatile可以实现变量更快的处理
class MyThread implements Runnable{
private volatile int ticket = 5; // 直接内存操作
@Override
public void run(){
synchronized(this){
while(this.ticket > 0){
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票处理,ticke = "+this.ticket -- );
}
}
}
}
public class ThreadDemo{
public static void main(String args[]){
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
面试题:请解释volatiel与synchronized?
‒ volatile主要在属性上使用,而synchronizesd是在代码块和方法上使用的
‒ volatile无法描述同步的处理,它只是一种直接的内存处理,避免了副本的操作,而synchronized是实现同步的