文档章节

守护线程的创建和运行

柳哥
 柳哥
发布于 2015/04/25 00:55
字数 921
阅读 290
收藏 5

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)这样的死循环)。

© 著作权归作者所有

共有 人打赏支持
柳哥
粉丝 203
博文 405
码字总数 347782
作品 0
杭州
技术主管
加载中

评论(1)

曾经的十字镐
曾经的十字镐
这不是吊胃口么。6
java中守护线程与用户线程

Java线程分为两类分别为daemon线程(守护线程)和User线程(用户线程),在JVM启动时候会调用main函数,main函数所在的线程是一个用户线程,这个是我们可以看到的线程,其实JVM内部同时还启动...

今天你不奋斗明天你就落后
2017/09/29
0
0
JAVA多线程05-基础篇-守护线程

本节摘要:介绍守护线程,代码示例 一、守护线程 thread 类中有一个isDaemon的布尔变量,如果isDaemon=true代表该线程为守护线程,否则为用户线程 1.1 守护线程特点 当所有用户线程结束时,程...

x_coder
2017/10/23
0
0
Java 多线程回顾

做java web开发,一直以来比较依赖java框架和oracle数据库的功能。因为一般遇到高并发的情况并不多,企业内软件多半用户数不多,即使偶尔遇到,也都在oracle数据库中处理了。 对java的多线程...

五大三粗
2015/11/25
9
0
多线程学习笔记(六)

在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源越多,也就是CPI优先执行优先级较高的线程对象中的任务. 设置线程优先级有助于帮线程规划器确定在下一次选择哪一个线程来优先...

scymore
2016/08/31
20
0
学习笔记2:java中Thread类与线程的创建

线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。 每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。...

牧羊人Berg
2015/10/15
38
0

没有更多内容

加载失败,请刷新页面

加载更多

Cointext在阿根廷和土耳其推出比特币现金短信钱包

Cointext于10月15日开始在土耳其和阿根廷提供新的基于SMS的比特币现金钱包服务,这两个国家的加密货币使用量急剧上升,以应对严峻的经济形势。 移动钱包 通过短信处理BCH交易 “比特币是更好...

lpy411
6分钟前
0
0
大数据早课-0918

9.18日早课 1.全局搜索含有abc的文件名称或文件夹的命令 2.当前目录一般用什么表示 3.切换到上一次和上一层命令分别是什么 4.pwd是查看当前目录的什么 5.隐藏文件或文件夹的标识是什么? 怎样...

hnairdb
7分钟前
0
0
mybatis学习笔记一

一、mybaits需要的项目依赖 <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artif......

wuyiyi
8分钟前
0
0
CentOS6 安装 GraphicsMagick

1.安装相关依赖: yum install -y gcc libpng libjpeg libpng-devel libjpeg-devel ghostscript libtiff libtiff-devel freetype freetype-devel 2.下载并解压到目录/usr/local/ wget ft......

凯文加内特
10分钟前
0
0
RabbitMq集群使用Nginx做负载均衡

1.配置rabbitmq集群(可以参考前一篇RabbitMq之部署集群) 2.Nginx做负载均衡 注意:Nginx1.90版本后 新增了stream 模块用于一般的 TCP 代理和负载均衡,之前版本不支持 修改Nginx配置文件ngi...

zhaochaochao
15分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部