用户线程和守护线程

在Java中线程分为两类:用户线程(User thread)和守护线程(Daemon thread)。

守护进程(Daemon)是运行在后台的一种特殊进程。它的作用是为其他线程的运行提供便利服务,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统同生共死因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。

垃圾回收线程就是一个经典的守护线程,当我们的程序中不再有任何运行的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是JVM上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。

守护线程和用户线程的没啥本质的区别:唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。

将线程转换为守护线程可以通过调用Thread对象的setDaemon(true)方法来实现。在使用守护线程时需要注意一下几点:

(1) thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。

(2) 在Daemon线程中产生的新线程也是Daemon的。

(3) 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

在父线程中建立一个子线程并将子线程设置为守护线程,当父线程结束时,子线程也随之结束。

如果没有将子线程设置为守护线程,当父线程结束时,子线程继续运行,并没有结束。

守护线程有一个应用场景,就是当主线程结束时,结束其余的子线程(守护线程)自动关闭,就免去了还要继续关闭子线程的麻烦。不过如果真有这种场景,还是用中断的方式实现比较合理。

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.TimeUnit;  
   
public class ThreadTest  
{  
   
    public static void main(String[] args)  
    {  
        Thread mainThread = new Thread(new Runnable(){  
            public void run()  
            {  
                System.out.println("主线程开始...");  
                Thread sonThread = new Thread(new Thread1(Thread.currentThread()));  
                sonThread.setDaemon(false);  
                sonThread.start();  
                   
                try 
                {  
                    TimeUnit.MILLISECONDS.sleep(10000);  
                }  
                catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
                System.out.println("主线程结束");  
            }  
        });  
        mainThread.start();  
    }  
       
}  
   
class Thread1 implements Runnable  
{  
    private Thread mainThread;  
       
    public Thread1(Thread mainThread)  
    {  
        this.mainThread = mainThread;  
    }  
       
    @Override 
    public void run()  
    {  
        while(mainThread.isAlive())  
        {  
            System.out.println("子线程运行中....");  
            try 
            {  
                TimeUnit.MILLISECONDS.sleep(1000);  
            }  
            catch (InterruptedException e)  
            {  
                e.printStackTrace();  
            }  
        }  
    }  
       
}

运行结果如下:

主线程开始... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
子线程运行中.... 
主线程结束

注意:不是说当子线程是守护线程,主线程结束,子线程就跟着结束,这里的前提条件是:当前jvm应用实例中没有用户线程继续执行,如果有其他用户线程继续执行,那么后台线程不会中断

import java.util.concurrent.TimeUnit;  
   
public class DaemonThreadTest  
{  
    public static void main(String[] args)  
    {  
        Thread mainThread = new Thread(new Runnable(){  
            @Override 
            public void run()  
            {  
                Thread childThread = new Thread(new ClildThread());  
                childThread.setDaemon(true);  
                childThread.start();  
                System.out.println("I'm main thread...");  
            }  
        });  
        mainThread.start();  
           
        Thread otherThread = new Thread(new Runnable(){  
            @Override 
            public void run()  
            {  
                while(true)  
                {  
                    System.out.println("I'm other user thread...");  
                    try 
                    {  
                        TimeUnit.MILLISECONDS.sleep(1000);  
                    }  
                    catch (InterruptedException e)  
                    {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        });  
        otherThread.start();  
    }  
}  
   
class ClildThread implements Runnable  
{  
    @Override 
    public void run()  
    {  
        while(true)  
        {  
            System.out.println("I'm child thread..");  
            try 
            {  
                TimeUnit.MILLISECONDS.sleep(1000);  
            }  
            catch (InterruptedException e)  
            {  
                e.printStackTrace();  
            }  
        }  
    }  
}

运行结果如下:

I'm other user thread... 
I'm child thread.. 
I'm main thread... 
I'm other user thread... 
I'm child thread.. 
I'm other user thread... 
I'm child thread.. 
I'm child thread.. 
I'm other user thread... 
I'm other user thread... 
I'm child thread..   
I'm child thread.. 
I'm other user thread... 
I'm child thread.. 
I'm other user thread... 
I'm child thread.. 
I'm other user thread... 
I'm child thread.. 
I'm other user thread... 
I'm child thread..(无限输出)

写java多线程程序时,一般比较喜欢用java自带的多线程框架,比如ExecutorService,但是java的线程池会将守护线程转换为用户线程,所以如果要使用后台线程就不能用java的线程池。
如下,线程池中将daemon线程转换为用户线程的程序片段:

static class DefaultThreadFactory implements ThreadFactory {  
    private static final AtomicInteger poolNumber = new AtomicInteger(1);  
    private final ThreadGroup group;  
    private final AtomicInteger threadNumber = new AtomicInteger(1);  
    private final String namePrefix;  
   
    DefaultThreadFactory() {  
        SecurityManager s = System.getSecurityManager();  
        group = (s != null) ? s.getThreadGroup() :  
                              Thread.currentThread().getThreadGroup();  
        namePrefix = "pool-" +  
                      poolNumber.getAndIncrement() +  
                     "-thread-";  
    }  
   
    public Thread newThread(Runnable r) {  
        Thread t = new Thread(group, r,  
                              namePrefix + threadNumber.getAndIncrement(),  
                              0);  
        if (t.isDaemon())  
            t.setDaemon(false);  
        if (t.getPriority() != Thread.NORM_PRIORITY)  
            t.setPriority(Thread.NORM_PRIORITY);  
        return t;  
    }  
}

注意到,这里不仅会将守护线程转变为用户线程,而且会把优先级转变为Thread.NORM_PRIORITY。

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.TimeUnit;  
   
public class DaemonThreadTest  
{  
    public static void main(String[] args)  
    {  
        Thread mainThread = new Thread(new Runnable(){  
            @Override 
            public void run()  
            {  
                ExecutorService exec = Executors.newCachedThreadPool();  
                Thread childThread = new Thread(new ClildThread());  
                childThread.setDaemon(true);  
                exec.execute(childThread);  
                exec.shutdown();  
                System.out.println("I'm main thread...");  
            }  
        });  
        mainThread.start();  
    }  
}  
   
class ClildThread implements Runnable  
{  
    @Override 
    public void run()  
    {  
        while(true)  
        {  
            System.out.println("I'm child thread..");  
            try 
            {  
                TimeUnit.MILLISECONDS.sleep(1000);  
            }  
            catch (InterruptedException e)  
            {  
                e.printStackTrace();  
            }  
        }  
    }  
}

运行结果如下:

I'm main thread...
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..(无限输出)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值