Day30.守护线程、定时器
作者:互联网
守护线程
- Java语言中线程分为两大类:
一类是:用户线程; 一类是:守护线程(后台线程);
注意:主线程main方法是一个用户线程。
守护线程中最具有代表性的就是:垃圾回收线程
- 守护线程的特点
守护线程一般是一个死循环,所有的用户线程只要结束,守护线程自动结束
- 守护线程用在什么地方呢?
如:每天24点时,系统数据自动备份
这个需要使用到定时器,我们可以将定时器设置为守护线程。
如果结束了,守护线程自动退出,没有必要进行数据备份了。
- 方法
void | setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 |
/*守护线程*/
public class ThreadTest11 {
public static void main(String[] args){
Thread t = new BakDataThread();
t.setName("备份数据的线程");
//启动线程之前,将线程设置为守护线程
t.setDaemon(true);
t.start();
//主线程:用户线程
for(int i = 0; i<10 ;i++){
System.out.println(Thread.currentThread().getName() + "--->"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class BakDataThread extends Thread{
public void run(){
int i = 0;
while (true){
System.out.println(Thread.currentThread().getName() + "--->" + (++i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
定时器
- 定时器的作用:
间隔特定的时间,执行特定的程序。
每周尽心银行账户的总账操作;每天进行数据的备份操作;
在实际开发中,这种需求很常见。
在java中,定时器可以使用多种方式实现
使用sleep方法,设置睡眠时间,到某个时间点醒来,执行任务。这种方式是最原始的定时器。
在java中的类库中已经写好了一个定时器:java.util.Timer,可以直接拿来用。这种方式在开发中也很少用,因为现在又很多的高级框架都是支持定时任务的。
实际开发中,使用较多的是Spring框架提供的SpringTask框架,这个框架只要进行简单的配置,就可以完成定时器任务。
- 构造方法
Timer() 创建一个新计时器。 |
Timer(boolean isDaemon) 创建一个新计时器,可以指定其相关的线程作为守护程序运行。 |
Timer(String name) 创建一个新计时器,具有指定的名称。 |
Timer(String name, boolean isDaemon) 创建一个新计时器,具有指定的名称,并且可以指定作为守护程序运行。 |
- 方法
void | schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务。 |
void | schedule(TimerTask task, Date firstTime, long period) 安排指定的任务在指定的时间开始进行重复的固定延迟执行。 |
void | schedule(TimerTask task, long delay) 安排在指定延迟后执行指定的任务。 |
void | schedule(TimerTask task, long delay, long period) 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。 |
void | cancel() 终止此计时器,丢弃所有当前已安排的任务。 |
int | purge() 从此计时器的任务队列中移除所有已取消的任务。 |
- 代码实现
/*使用定时器指定定时任务*/
public class TimerTest {
public static void main(String[] args) throws ParseException {
//创建定时器对象
Timer timer = new Timer();
//Timer timer = new Timer(true); 守护线程的方式
//第一次执行时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date firstTime = sdf.parse("2022-01-15 11:37:00");
//指定定时任务
//timer.schedule(定时任务,第一次执行时间,间隔多久执行一次);
timer.schedule(new LogTimerTask(),firstTime,1000*10);
}
}
//编写一个定时任务类:假设这是一个记录日志的定时任务
class LogTimerTask extends TimerTask{
@Override
public void run() {
//编写需要执行的任务
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(new Date());
System.out.println(strTime+ "完成了一次数据备份!");
}
}
实现线程的第三种方式 :实现Callble接口(JDK8新特性)
思考:系统委派一个线程去执行一个任务,该线程执行完任务之后,可能会有一个执行结果,我们怎么能拿到这个执行结果呢?
-
实现Callble接口:
优点:这种方式实现的线程可以获取线程的返回值
缺点:这种方式执行效率较低,在获取线程执行结果时,当前线程会受到阻塞。
/*实现线程的第三种方式:
实现Callable接口*/
public class ThreadTest12 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//第一步: 创建一个"未来任务类"对象 (以下使用了匿名内部类的方式)
//参数非常重要,需要给一个Callble接口实现类对象
FutureTask task = new FutureTask(new Callable() {
@Override
public Object call() throws Exception { //cal;()方法相当于run方法
//线程执行任务,执行之后可能会有一个执行结果
System.out.println("call method begin");
Thread.sleep(1000*10);
System.out.println("call method end");
int a = 100; int b = 200;
return a+b; //自动装箱
}
});
//创建线程对象
Thread t = new Thread(task);
//启动线程
t.start();
//在主线程中,怎么获取t线程的返回结果?
Object obj = task.get();
//这里的程序执行必须要等待get()方法执行结束,
//而gat方法拿到执行结果需要等task线程执行结束
//所以线程会受阻,进入阻塞状态
}
}
- FutureTask类方法
FutureTask(Callable<V> callable) 创建一个 FutureTask,一旦运行就执行给定的 Callable。 |
FutureTask(Runnable runnable, V result) 创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。 |
V | get() 等待计算完成,然后获取其结果。 |
V | get(long timeout, TimeUnit unit) 最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 |
boolean | isDone() 如果任务已完成,则返回 true。 |
boolean | cancel(boolean mayInterruptIfRunning) 试图取消对此任务的执行。 |
标签:定时器,Day30,任务,线程,new,执行,守护 来源: https://blog.csdn.net/a111042555/article/details/122507051