在Java中,一个线程对象是有自己的生命周期的,如果想要控制好线程的生命周期,则首先应该认识其生命周期,如图。
从图中可以发现,大部分线程生命周期的方法都已经学过了,那么这里主要介绍下面3种新方法。
1.停止多线程:public void stop()。
2.挂起线程:public final void suspend()、暂停执行。
3.恢复挂起的线程执行:public final void resume()。
但这3种方法会产生死锁问题,所以从JDK1.2开始已经不推荐使用。那么如何停止一个线程的执行呢?可以通过标志位的方式停止。
范例:优雅地停止线程运行
package cn.kuiba.util;
public class Main{
public static boolean flag=true; //线程停止标记
public static void main(String[] args)throws Exception{
new Thread(()->{ //新的线程对象
long num=0;
while (flag){ //判断标记
try {
Thread.sleep(50);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在运行、num="+num++);
}
},"执行线程").start();
Thread.sleep(200); //运行200毫秒
flag=false; //停止线程,修改执行标记
}
}
本程序为了可以停止线程运行,所以专门定义了flag属性,随后利用对flag属性内容的修改实现了停止线程执行的目的。
提示:线程的完整运行状态
14.7 后台守护线程
Java中的线程分为两类:用户线程和守护线程。守护线程(Daemon)是一种运行在后台的线程服务线程,当用户线程存在时,守护线程也可以同时存在;当用户线程全部消失时,守护线程也会消失。
Java中的线程都是通过Thread类来创建的,用户线程和守护线程处理运行模式的区别外,其他完全相同。通过如表所示的方法进行守护线程操作。
范例:使用守护线程
package cn.kuiba.util;
public class Main{
public static void main(String[] args)throws Exception{
Thread userThread = new Thread(()->{
for (int x=0;x<2;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(); //启动守护线程
}
}
程序执行结果:
守护线程正在运行、x=0
用户线程正在运行、x=0
用户线程正在运行、x=1
守护线程正在运行、x=1
本程序定义了一个守护线程,并且该守护线程将一直进行信息的输出,但是通过执行的结果可以发现,当用户线程消失后守护线程也同时结束。
14.8 volatile关键字
在多线程编程中,若干个线程为了可以实现公共资源的操作,往往是复制相应变量的副本,待操作完成后再将此副本变量数据与原始变量进行同步处理。如果想要直接进行原始变量的操作,节约复制变量副本与同步的时间的话,则可以再变量声明时使用volatile关键字。
范例:使用volatile关键字定义变量
package cn.kuiba.util;
class MyThread implements Runnable{
private volatile int ticket=3; //直接内存操作
@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()+"卖票处理,ticket="+this.ticket--);
}
}
}
}
public class Main{
public static void main(String[] args)throws Exception{
MyThread mt =new MyThread();
new Thread(mt,"售票员A").start();
new Thread(mt,"售票员B").start();
new Thread(mt,"售票员C").start();
}
}
程序执行结果:
售票员A卖票处理,ticket=3
售票员A卖票处理,ticket=2
售票员A卖票处理,ticket=1
本程序在定义ticket属性时使用了volatile关键字进行定义,这样就表示该变量在进行操作时将直接会进行原始变量内容的处理。