守护线程的创建和运行
博客专区 > 柳哥 的博客 > 博客详情
守护线程的创建和运行
柳哥 发表于3年前
守护线程的创建和运行
  • 发表于 3年前
  • 阅读 277
  • 收藏 5
  • 点赞 0
  • 评论 1

腾讯云 技术升级10大核心产品年终让利>>>   

Java里有一种特殊的线程叫做守护(daemon)线程。这种线程的优先级很低,通常来说,当同一个应用程序里没有其它的线程运行的时候,守护线程才运行。当守护线程是程序中唯一运行的线程时,守护线程执行结束后,JVM也就结束了这个程序。

因为这种特性,守护线程通常被用来做为同一程序中普通线程(也称为用户线程)的服务提示者。它们通常是无限循环的,以等待服务请求或执行线程的任务。它们不能做重要的工作,因为我们不可能知道守护线程什么时候能够获取CPU时钟,并且,在没有其他线程运行的时候,守护线程随时可能结束。一个典型的守护线程是java的垃圾回收器(Garbage Collector)。

范例程序包含两个线程:一个是用户线程,它将事件写入到一个队列中;另一个是守护线程,它将管理这个队列,如果生成的事件超过10秒钟,就会被移除。

package concurrency;

import java.util.Date;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

public class Main1 {
    public static void main(String[] args) {
        LinkedBlockingDeque<Event> deque = new LinkedBlockingDeque<Event>();
        WriterTask writer = new WriterTask(deque);
        for(int i = 0;i < 3; i++){
            Thread thread = new Thread(writer);
            thread.start();
        }
        CleanerTask cleaner = new CleanerTask(deque);
        cleaner.start();
    }
}

class Event{
    private Date date;
    private String event;
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getEvent() {
        return event;
    }
    public void setEvent(String event) {
        this.event = event;
    }
}

class WriterTask implements Runnable{
    private LinkedBlockingDeque<Event> deque;
    public WriterTask(LinkedBlockingDeque<Event> deque){
        this.deque = deque;
    }
    public void run() {
        for(int i = 1; i <= 20; i++){
            Event event = new Event();
            event.setDate(new Date());
            event.setEvent(String.format("The thread %s has generated an event", 
                Thread.currentThread().getId()));
            deque.addFirst(event);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class CleanerTask extends Thread{
    private LinkedBlockingDeque<Event> deque;
    public CleanerTask(LinkedBlockingDeque<Event> deque){
        this.deque = deque;
        this.setDaemon(true);
    }
    @Override
    public void run() {
        while(true){
            Date date = new Date();
            clean(date);
        }
    }
    private void clean(Date date){
        long difference;
        boolean delete;
        if(deque.size() == 0) return;
        delete = false;
        do {
            Event e = deque.getLast();
            difference = date.getTime() - e.getDate().getTime();
            if(difference > 10000){
                System.out.printf("Cleaner: %s\n", e.getEvent());
                deque.removeLast();
                delete = true;
            }
        } while (difference > 10000);
        if(delete){
            System.out.printf("Cleaner: Size of the queue : %d\n", deque.size());
        }
    }
}

对程序的运行输出进行分析之后,我们会发现,队列中的对象会不断增长直到30个,然后到程序结束,队列的长度维持在27~30之间。

这个程序有3个WriterTask线程,每个线程向队列写入一个事件,然后休眠1秒钟。在第一个10秒钟内,队列中有30个事件,直到3个WriterTask都休眠后,CleanerTask才开始执行,但是它没有删除任何事件。因为所有的事件都小于10秒钟。在接下来的运行中,CleanerTask每秒删除3个对象,同时WriterTask会写入3个对象,所以队列的长度一直介于27~30之间。

setDaemon()方法只能在start()方法被调用之前设置。一旦线程开始运行,将不能再修改守护状态。isDaemon()方法被用来检查一个线程是不是守护线程,返回值true,表示这个线程是守护线程; false表示这个线程是用户线程。

注意:1. thread.setDaemon(true)必须在thread.start()之前设置。2. 在Daemon线程中产生的新线程也是Daemon的。新创建一个新Thread对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护线程。3. 当用户线程(非守护线程)全部结束,则守护线程也随即结束,否则守护线程将一直执行(不管你的守护线程业务逻辑是不是while(true)这样的死循环)。

共有 人打赏支持
粉丝 200
博文 394
码字总数 347782
评论 (1)
曾经的十字镐
这不是吊胃口么。6
×
柳哥
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: