Loading

Java学习笔记 - 多线程2

生产者&消费者模型

  • wait & notify 方法不是线程对象的方法,是普通java对象的都有的方法

  • wait & notify方法建立在线程同步的基础之上。因为多线程要同时操作一个对象,有线程安全问题

  • wait(): o.wait()让正在o对象上活动的线程t进入等待状态,并且释放掉之前占有对象o的锁

  • notify(): o.notify()让正在o对象上等待的线程唤醒,只是通知,不会释放掉之前占有对象o的锁

示例程序:

public class ProducerAndConsumer {
    public static void main(String[] args) {
        List list = new ArrayList();

        Producer pro = new Producer(list);
        Consumer con = new Consumer(list);

        pro.setName("生产者进程");
        con.setName("消费者进程");

        pro.start();
        con.start();
    }

}

//生产者线程类
class Producer extends Thread{
    private List list;

    public Producer(List list){
        this.list = list;
    }
    @Override
    public void run() {
        //一直生产
        while (true){
            synchronized (list){
                if(list.size() > 0){
                    try {
                        //当前线程进入等待状态,并且释放Producer之前占有的list的锁
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //程序能执行到这里说明仓库是空的,可以生产
                Object obj = new Object();
                list.add(obj);
                System.out.println(Thread.currentThread().getName() + "-->" + obj);
                //唤醒消费者进行消费:唤醒list对象上正在等待的线程,但不会释放之前占有的list的锁
                list.notify();
            }
        }
    }
}

//消费者线程类
class Consumer extends Thread{
    private List list;

    public Consumer(List list){
        this.list = list;
    }

    @Override
    public void run() {
        while (true){
            synchronized (list){
                if(list.size() == 0){
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //程序能执行到这里说明仓库是满的,可以消费
                Object obj = list.remove(0);
                System.out.println(Thread.currentThread().getName() + "-->" + obj);

                //唤醒生产者进行生产:唤醒list对象上正在等待的线程,但不会释放之前占有的list的锁
                list.notify();
            }
        }
    }
}

守护线程

  • 守护线程:后台线程,例如垃圾回收线程
  • 特点:一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束
  • 方法:final void setDaemon(boolean on) true表示设置调用线程为守护线程

示例程序:

public class ProtectedThreadTest {
    public static void main(String[] args) {
        BakDataThread bdt = new BakDataThread();

        //设置线程为守护线程,所有的用户线程都结束,守护线程会自动结束
        bdt.setDaemon(true);

        bdt.start();
        
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程运行  ---》》" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class BakDataThread extends Thread{
    @Override
    //方法覆盖不能比之前的方法抛出更多的异常,所以只能采用try catch的处理方式
    public void run() {
        int i = 0;
        while (true){
            System.out.println("守护线程运行---》》" + i++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

定时器

  • 作用:间隔特定的时间,执行特定的程序
  • 在java的类库中已经写好了一个定时器:java.util.Timer

实现步骤

  • 1.创建定时器 public Timer(boolean isDaemon)
  • 2.调用schedule方法:void schedule(TimerTask task, Date firstTime, long period)
    参数:抽象类TimerTask; 第一次的执行时刻; 执行间隔时间/毫秒

示例代码

public class TimerTest {
    public static void main(String[] args) throws ParseException {
        //创建定时器
        Timer timer = new Timer();
        //Timer timer = new Timer(true);   //true:表示作为一个守护线程运行

        //指定起始执行时刻
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date firstTime = sdf.parse("2020-05-31 13:08:10");
        
        //第一种方式:使用匿名内部类的方式,实现抽象类TimerTask
        //从firstTime开始,每period毫秒执行一次run()方法
        timer.schedule(new 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 + " : 完成了一次数据备份");
            }
        },firstTime,1000 * 10);
    }
}

// 第二种方法:编写定时任务类,实现抽象类TimerTask
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 + " : 完成了一次数据备份");
    }
}
posted @ 2020-06-02 12:06  Krocz  阅读(140)  评论(0编辑  收藏  举报