守护线程
- 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();
            }
        }
    }
} 
定时器
- 定时器的作用:
 
间隔特定的时间,执行特定的程序。
每周尽心银行账户的总账操作;每天进行数据的备份操作;
在实际开发中,这种需求很常见。
- 构造方法
 
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)试图取消对此任务的执行。  | 










