zoukankan      html  css  js  c++  java
  • 死锁、Lock锁、等待唤醒机制、线程组、线程池、定时器、单例设计模式_DAY24

    1:线程(理解)

        (1)死锁

           概念:

               同步中,多个线程使用多把锁之间存在等待的现象。

           原因分析:

             a.线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码,

               但是此时,两个锁均处于锁死状态。最终导致两线程相互等待,进入无限等待状态。

              b.有同步代码块的嵌套动作。

            解决方法:

              不要写同步代码块嵌套。

           例子:cn.itcast2.DeadLockThread;  cn.itcast2.demo

    package cn.itcast2;
    
    public class DeadLockThread extends Thread {
    
        boolean flag;//定义标记,用来指定要执行的代码
        public DeadLockThread(boolean flag) {
            this.flag = flag;
        }
    
        @Override
        public void run() {
            if(flag) {//flag赋值为true时,执行的代码
                synchronized (Demo.LOCK1) {
                    System.out.println("if中锁1");
                    /*try {      //加上睡眠时间,就不正常了,有可能会出现死锁现象
                        sleep(100l);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }*/
                    synchronized (Demo.LOCK2) {
                        System.out.println("if中锁2");
                    }
                }
            } else {//flag赋值为false时,执行的代码
                try { //加上睡眠时间,等线程1执行完,就正常了,不会出现死锁现象
                        sleep(100l);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                synchronized (Demo.LOCK2) {
                    System.out.println("else中锁2");
                    synchronized (Demo.LOCK1) {
                        System.out.println("else中锁1");
                    }
                }
            }
        }
    }
    View Code
    package cn.itcast2;
    /*
     * 线程死锁:
     *         线程锁相互等待
     */
    public class Demo {
    
        public static final Object LOCK1 = new Object();
        public static final Object LOCK2 = new Object();
        
        public static void main(String[] args) {
            
            DeadLockThread dlt = new DeadLockThread(true);
            DeadLockThread dlt2 = new DeadLockThread(false);
            
            dlt.start();
            dlt2.start();
        }
        
    }
    View Code

        (2)JDK5的新特性:Lock

           它把什么时候获取锁,什么时候释放锁的时间给明确了。

           例子:cn.itcast.demo3  cn.itcast.MyTicket

    package cn.itcast;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /*
     * Lock锁:
     *         就是实现同步的另外的一种锁。另外的一种同步操作。
     *         Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
     * 
     *         子类对象:ReentrantLock
     * 
     *         public void lock() 上锁
     *         public void unlock()  解锁
     */
    public class Demo3 {
    
        public static final Object MY_LOCK = new Object();
        public static final Lock MY_LOCK2 = new ReentrantLock();
        
        public static void main(String[] args) {
            
            MyTicket mt = new MyTicket();
            
            Thread thread = new Thread(mt,"唐嫣");
            Thread thread2 = new Thread(mt,"柳岩");
            Thread thread3 = new Thread(mt,"高圆圆");
            
            thread.start();
            thread2.start();
            thread3.start();
        }
    
    }
    View Code
    package cn.itcast;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyTicket implements Runnable {
    
        private int number = 100;
        Lock lock = new ReentrantLock();
        
        @Override
        public void run() {
    
            //卖票的动作
            while(true) {
                
    //            synchronized(Demo3.MY_LOCK){
                    lock.lock();
    //                Demo3.MY_LOCK2.lock();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    if(number>0) {
                        System.out.println(Thread.currentThread().getName()+":"+number--);
                    }
                    lock.unlock();
    //                Demo3.MY_LOCK2.unlock();
    //            }
            }
            
        }
    
    }
    View Code

        (3)线程间的通信(生产者与消费者问题)

           不同种类的线程针对同一个资源的操作。生产者线程生产与消费者线程消费,操作同一数据。

           例子:cn.itcast3.*

    package cn.itcast3;
    
    public class CRunnable implements Runnable {
        Person p;
    
        public CRunnable(Person p) {
            this.p = p;
        }
    
        @Override
        public void run() {
            while (true) {
                synchronized (p) {
                    //c
                    System.out.println(p);
                }
            }
        }
    
    }
    View Code
    package cn.itcast3;
    /*
     * 生产者消费者问题:
     *         
     *         共享数据:一个Person对象
     *         生产者:为该对象属性赋值
     *         消费者:获取对象属性值
     * 
     * 采取第二种方式完成。
     */
    public class Demo {
    
        public static void main(String[] args) {
    
            Person person = new Person();
            //生产线程运行目标
            PRunnable p = new PRunnable(person);
            //消费线程运行目标
            CRunnable c = new CRunnable(person);
            //创建生产线程
            Thread pThread = new Thread(p);
            //创建消费线程
            Thread cThread = new Thread(c);
            //开启消费与生产
            pThread.start();
            cThread.start();
        }
    
    }
    View Code
    package cn.itcast3;
    /*
     * 被共享的对象对应的类
     */
    public class Person {
    
        private String name;
        private int age;
    
        public Person() {
            super();
        }
    
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    View Code
    package cn.itcast3;
    /*
     * 生产者线程执行目标
     */
    public class PRunnable implements Runnable {
        
        Person p;
        int x = 0;
        
        public PRunnable(Person p) {
            this.p = p;
        }
    
        @Override
        public void run() {
    
            while(true) {
                synchronized (p) {
                    if (x % 2 == 0) {
                        p.setName("唐嫣");
                        p.setAge(28);
                    } else {
                        p.setName("刘正风");
                        //p
                        p.setAge(29);
                    }
                    x++;
                }
            }
        }
    
    }
    View Code

        (4)等待唤醒机制

           涉及并非是Thread类的方法,而是Object类的两个方法:因为锁可以为共享数据本身可以是任意的对象,在runnable中进行等待唤醒当前所在线程。

           等待:

               public final void wait() throws InterruptedException

               让当前线程进入等待状态,如果线程进入该状态,不唤醒或打断,不会解除等待状态。

               进入等待状态时会释放锁。

           唤醒:

               public final void notify()

               唤醒正在等待的线程。

               继续等待之后的代码执行。

           sleepwait的区别:

               sleep指定时间,wait可指定可不指定。

               sleep释放执行权,不释放锁。因为一定可以醒来。

               wait释放执行权与锁。

           例子:cn.itcast4.*

    package cn.itcast4;
    
    /*
     * 消费者线程执行目标
     */
    public class CRunnable implements Runnable {
        Person p;
    
        public CRunnable(Person p) {
            this.p = p;
        }
    
        // 判断>>生产/消费>>修改标志位>>唤醒
        @Override
        public void run() {
            while (true) {
                synchronized (p) {
                    // 判断是否有数据
                    if (!p.flag) {// 如果没有数据,消费者等待
                        try {
                            p.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
    
                    // 消费
                    // System.out.println(p);
                    System.out.println(p.getName() + ":" + p.getAge());
                    // 将数据标志位,置为没有值的false
                    p.flag = false;
                    // 唤醒正在等待的其他线程
                    p.notify();
                }
            }
        }
    
    }
    View Code
    package cn.itcast4;
    /*
     * 生产者消费者问题:
     *         
     *         共享数据:一个Person对象
     *         生产者:为该对象属性赋值
     *         消费者:获取对象属性值
     * 
     * 采取第二种方式完成。
     */
    public class Demo {
    
        public static void main(String[] args) {
    
            Person person = new Person();
            //生产线程运行目标
            PRunnable p = new PRunnable(person);
            //消费线程运行目标
            CRunnable c = new CRunnable(person);
            //创建生产线程
            Thread pThread = new Thread(p);
            //创建消费线程
            Thread cThread = new Thread(c);
            //开启消费与生产
            pThread.start();
            cThread.start();
        }
    
    }
    View Code
    package cn.itcast4;
    /*
     * 被共享的对象对应的类
     */
    public class Person {
    
        private String name;
        private int age;
        //标记是否有数据。true为有数据,需要消费。false没有数据,需要生产。
        boolean flag = false;
    
        public Person() {
            super();
        }
    
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    View Code
    package cn.itcast4;
    
    /*
     * 生产者线程执行目标
     */
    public class PRunnable implements Runnable {
    
        Person p;
        int x = 0;
    
        public PRunnable(Person p) {
            this.p = p;
        }
    
        // 判断>>生产/消费>>修改标志位>>唤醒
        @Override
        public void run() {
    
            while (true) {
                synchronized (p) {
                    // 判断是否有数据
                    if (p.flag) {// 如有有数据,生产者等待
                        try {
                            p.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 生产
                    if (x % 2 == 0) {
                        p.setName("唐嫣");
                        p.setAge(28);
                    } else {
                        p.setName("刘正风");
                        p.setAge(29);
                    }
                    x++;
    
                    // 将数据标志位,置为有值的true
                    p.flag = true;
                    // 唤醒正在等待的其他线程
                    p.notify();
                }
            }
        }
    
    }
    View Code

         (5)线程组

           多个线程出现时,可以将线程分组,统一处理。

           涉及线程组类:ThreadGroup

           注意:

               线程组可以包含线程或者线程组。

               当前线程只能访问所在线程组或者子组。不能访问父组或者兄弟组。

               如果没有指定线程组,则属于main线程组。

           主要方法:

               public final String getName()

               public final void setDaemon(boolean?daemon)

               无线程添加方法,设置线程组在Thread构造方法中。

           例子:cn.itcast5.demo

    package cn.itcast5;
    /*
     * 线程组:
     *         多个线程出现时,可以将线程分组,统一处理
     *         Thread相关线程组的方法:
     *             public Thread(ThreadGroup group,Runnable target,String name)
     *             public final ThreadGroup getThreadGroup()
     *         ThreadGroup:
     *             public final String getName()
     */
    public class Demo {
    
        public static void main(String[] args) {
            
            ThreadGroup tg = new ThreadGroup("唐嫣的小组");
            Thread thread = new Thread(tg, new Runnable() {
                
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println(i);
                    }
                }
            },"线程1");
            
            Thread thread2 = new Thread(new Runnable() {
                
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println(i);
                    }
                }
            },"线程1");
            
            System.out.println("thread:"+thread.getThreadGroup().getName()); //thread:唐嫣的小组
            System.out.println("thread2:"+thread2.getThreadGroup().getName()); //thread2:main
            System.out.println("main:"+Thread.currentThread().getThreadGroup().getName()); //main:main
            
        }
    }
    View Code

     

         (6)线程池

          将线程放置到同一个线程池中,其中的线程可以反复使用,无需反复创建线程而消耗过多资源。

          Executors:线程池创建工厂类

            返回线程池方法(还有其他方法) public static ExecutorService newFixedThreadPool(int?nThreads)

          ExecutorService:线程池类

             主要方法:

                 Future<?> submit(Runnable?task)

                 <T> Future<T> submit(Callable<T>?task)

                 void shutdown()

            注意:

                线程池提交方法后,程序并不终止,是因为线程池控制了线程的关闭等。

                Callable:相当于有返回值类型的runnable

                Future是将结果抽象的接口。可以将线程执行方法的返回值返回。

          例子:cn.itcast5.demo2

    package cn.itcast5;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /*
     * 线程池:用来存放线程。
     * 一、Executors:线程池工厂类
     * 主要方法:
     * public static ExecutorService newFixedThreadPool(int nThreads)
     * 
     *二、 ExecutorService接口
     * 主要方法:
     * 1、Future<?> submit(Runnable task)
     * 2、<T> Future<T> submit(Callable<T> task)
     * 3、void shutdown()
     */
    public class Demo2 {
    
        public static void main(String[] args) {
            
            //使用线程池工厂创建线程池对象
            ExecutorService es = Executors.newFixedThreadPool(2);
            
            //使用线程池,第一次提交runnable
            es.submit(new Runnable(){
    
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        System.out.println("第一次:"+i);
                    }
                }});
    
            //使用线程池,第二次提交runnable
            es.submit(new Runnable(){
    
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        System.out.println("第二次"+i);
                    }
                }});
            
            //不一定要关闭,但是这里关闭了线程池
            es.shutdown();
        }
    }
    View Code

     

         (7)线程实现的第三种方式

          a.使用线程池工厂创建线程池对象  : ExecutorService es = Executors.newFixedThreadPool(2);

          b.实现Callable接口,public public class MyCallable implements Callable<String>{},然后重写其中的call()方法,相当于runnable中的run()方法

          c.创建Callable类的实例对象  : MyCallable mc = new MyCallable();

          d.线程池提交Callable,返回Future结果 :  Future<String> submit2 = es.submit(mc);

          e.通过Future对象获取call方法的返回结果: System.out.println(submit2.get());

          例子:cn.itcast5.MyCallable   cn.itcast5.demo3

    package cn.itcast5;
    
    import java.util.concurrent.Callable;
    
    /*
     * 定义一个Callable类。
     * 实现多线程的第三种方式。
     */
    public class MyCallable implements Callable<String>{
    
        //重写call方法,相当于runnable中的run方法
        @Override
        public String call() throws Exception {
            return "经过多线程的学习,我发现,编程真的很有意思!";
        }
    
    }
    View Code
    package cn.itcast5;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    /*
     *  
     * Future<?> submit(Runnable task)
     * <T> Future<T> submit(Callable<T> task)
     * 
     * Future:线程执行返回结果
     * V get()
          throws InterruptedException,
                 ExecutionException   返回计算结果
       Callable:
     */
    public class Demo3 {
    
        public static void main(String[] args) throws Exception {
            
            //使用线程池工厂创建线程池对象
            ExecutorService es = Executors.newFixedThreadPool(2);
            
            //使用线程池,提交runnable
            Future<?> submit = es.submit(new Runnable(){
    
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        System.out.println(i);
                    }
                }});
            
            Object object = submit.get();
            System.out.println(object);  //输出结果 null
            
            //实现多线程的第三种方式。
            //创建Callable类的实例对象
            MyCallable mc = new MyCallable();
            //线程池提交Callable,返回Future结果
            Future<String> submit2 = es.submit(mc);
            System.out.println(submit2); //打印的是地址
            //通过Future对象获取call方法的返回结果。
            System.out.println(submit2.get()); // call()方法返回的内容:经过多线程的学习,我发现,编程真的很有意思!
        }
    
    }
    View Code

     

         (8)定时器

            定时器:Timer

               构造方法:

                  public Timer()

               主要方法:

                  public void schedule(TimerTask task, Date time) 指定时间点完成指定任务

                  public void schedule(TimerTask task,Date firstTime,long period) 指定第一次开始时间和后边重复执行的时间完成指定任务

                  public void schedule(TimerTask task, long delay)  在指定时间后执行指定任务一次

                  public void schedule(TimerTask task,long delay, long period)  指定时间后执行指定任务第一次,再在每指定时间后,执行指定任务

           定时器任务类:TimerTask  (实现了Runnable接口)

               public abstract void run()  要重写的真正执行的代码

           针对于cancel()方法:

               定时器的该方法终止定时器的。

               定时器任务的该方法用来取消该定时器任务的任务。

           例子:cn.itcast5.demo4 ; cn.itcast5.MyTask

    package cn.itcast5;
    
    import java.util.Date;
    import java.util.Timer;
    
    /*
     * 定时器:Timer类
     *         构造方法:
     *             public Timer()
     *         主要方法:
     *             public void schedule(TimerTask task, Date time) 指定时间点完成指定任务
     *             public void schedule(TimerTask task,Date firstTime,long period) 指定第一次开始时间和后边重复执行的时间完成指定任务
     *             public void schedule(TimerTask task, long delay)  在指定时间后执行指定任务一次
     *             public void schedule(TimerTask task,long delay, long period)  指定时间后执行指定任务第一次,再在每指定时间后,执行指定任务
     * 定时器任务类:TimerTask  实现了Runnable接口
     *         public abstract void run()  要重写的真正执行的代码
     * 
     * 针对于cancel()方法:
     *         定时器的该方法终止定时器的。
     *         定时器任务的该方法用来取消该定时器任务的任务。
     */
    public class Demo4 {
    
        public static void main(String[] args) {
    
            //创建定时器对象
            Timer timer = new Timer();
            
            //创建定时器任务对象
            MyTask myTask = new MyTask();
            
            //调用计划执行方法
            //定时器不可以重复schedule任务
    //        timer.schedule(myTask, new Date(), 3000);               
    //        timer.schedule(myTask, new Date(new Date().getTime()+3000), 5000);  
             
    //        myTask.cancel();  任务不能先取消再执行。
            timer.schedule(myTask, 3000, 5000);
            
    //        myTask.cancel();  //定时器任务的该方法用来取消该定时器任务的任务,定时器不会终止。
    //        timer.cancel();   //定时器的该方法终止定时器的。
        }
    
    }
    View Code
    package cn.itcast5;
    
    import java.util.TimerTask;
    /*
     * 定义搞一个TimerTask实际类
     */
    public class MyTask extends TimerTask {
    
        @Override
        public void run() {
    
            System.out.println("地震了!");
        }
    
    }
    View Code

        (9)最简单的线程程序代码:

           new Thread() {

               public void run() {

                  for(int x=0; x<100; x++) {

                      System.out.println(x);

                  }

               }

           }.start();

     

           new Thread(new Runnable(){

               public void run() {

                  for(int x=0; x<100; x++) {

                      System.out.println(x);

                  }

               }

           }).start();

     

    2:单例设计模式(理解 面试)

        (1)保证类在内存中只有一个对象。

        (2)怎么保证:

           A:构造私有

           B:自己造一个对象

           C:提供公共访问方式

        (3)两种方式:

           A:懒汉式(面试)

               public class Student {

                  private Student(){}

     

                  private static Student s = null;

     

                  public synchronized static Student getStudent() {

                      if(s == null) {

                         s = new Student();

                      }

                      return s;

                  }

               }

     

     

           B:饿汉式(开发)

               public class Student {

                  private Student(){}

     

                  private static Student s = new Student();

     

                  public static Student getStudent() {

                      return s;

                  }

               }

        (4)JDK的一个类本身也是单例模式的。

           Runtime

        (5)例子:cn.itcast5.Demo5  cn.itcast5.SinglePerson2   cn.itcast5.SinglePerson

    package cn.itcast5;
    
    public class Demo5 {
    
        public static void main(String[] args) {
    
    //        SinglePerson sp = new SinglePerson("唐嫣", 28);
    //        SinglePerson sp2 = new SinglePerson("唐嫣", 28);
            
            //饿汉式对象
            SinglePerson sp = SinglePerson.getInstance();
            SinglePerson sp2 = SinglePerson.getInstance();
            
            System.out.println(sp==sp2);
            //懒汉式对象
            SinglePerson2 sp3 = SinglePerson2.getInstance();
            SinglePerson2 sp4 = SinglePerson2.getInstance();
            
            System.out.println(sp3==sp4);
            
        }
    
    }
    View Code
    package cn.itcast5;
    /*
     * 懒汉式单例
     */
    public class SinglePerson2 {
    
        private static final Object LOCK = new Object();
        private String name;
        private int age;
        
        //定义一个private,static修饰的成员变量,类型是自己。
        private static SinglePerson2 sp;
        
        //经构造方法私有化,外界无法创建对象,只能自己创建自己
        private SinglePerson2(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
        //定义一个公共的,静态的,返回值类型为自己的的获取实例对象的方法。不考虑多线程
    //    public static SinglePerson2 getInstance() {
    //        if(sp==null) {
    //            System.out.println("没有对象");
    //            sp = new SinglePerson2("唐嫣", 28);
    //        }
    //        return sp;
    //    }
        //定义一个公共的,静态的,返回值类型为自己的的获取实例对象的方法。考虑多线程,使用代码块,不考虑效率
    //    public static SinglePerson2 getInstance() {
    //        
    //        synchronized (SinglePerson2.LOCK) {
    //            if (sp == null) {
    //                System.out.println("没有对象");
    //                sp = new SinglePerson2("唐嫣", 28);
    //            }
    //        }
    //        
    //        return sp;
    //    }
    
        //定义一个公共的,静态的,返回值类型为自己的的获取实例对象的方法。考虑多线程,使用同步方法,不考虑效率
    //    public static synchronized SinglePerson2 getInstance() {
    //        
    //            if (sp == null) {
    //                System.out.println("没有对象");
    //                sp = new SinglePerson2("唐嫣", 28);
    //            }
    //        
    //        return sp;
    //    }
        
        //定义一个公共的,静态的,返回值类型为自己的的获取实例对象的方法。考虑多线程,使用代码块,考虑效率
        public static SinglePerson2 getInstance() {
            
            if(sp==null) {  //如果没有对象,才进行同步操作
                synchronized (SinglePerson2.LOCK) {
                    if (sp == null) { //同步操作过程中,必须判断的条件
                        System.out.println("没有对象");
                        sp = new SinglePerson2("唐嫣", 28);
                    }
                }
            }
            
            return sp;
        }
        
        @Override
        public String toString() {
            return "SinglePerson [name=" + name + ", age=" + age + "]";
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    View Code
    package cn.itcast5;
    /*
     * 饿汉式单例
     */
    public class SinglePerson {
    
        private String name;
        private int age;
        
        //定义一个private,static修饰的成员变量,类型是自己。
        private static SinglePerson sp = new SinglePerson("唐嫣", 28);
        
        //经构造方法私有化,外界无法创建对象,只能自己创建自己
        private SinglePerson(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
        //定义一个公共的,静态的,返回值类型为自己的的获取实例对象的方法。
        public static SinglePerson getInstance() {
            return sp;
        }
        
        @Override
        public String toString() {
            return "SinglePerson [name=" + name + ", age=" + age + "]";
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        
        
    }
    View Code

     3、习题

    (1)、使用定时器完成下列需求:某地区每隔1秒地震一次,当震过5次时,不再地震。

    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /*
     * 使用定时器完成下列需求:让某地区每隔1秒地震一次,当震过5次时,不再地震。(将地震打印五次,停止定时器,要用到定时器任务)
     */
    public class Test {
    
        public static void main(String[] args) {
    
            //定义计时器
            Timer timer = new Timer();
            
            //创建定时器任务对象
            MyTask mt = new MyTask(5,timer);
            
            //计划执行任务
            timer.schedule(mt, new Date(), 1000);
            
    //        //关闭计时器
    //        timer.cancel();    //不能在此处直接关
        }
    
    }
    
    //定义计时器任务类
    class MyTask extends TimerTask {
    
        private int times;
        private Timer timer;
        
        public MyTask(int times, Timer timer) {
            super();
            this.times = times;
            this.timer = timer;
        }
    
        @Override
        public void run() {
            
            if(times>0) {
                System.out.println("地震了!");
            }else  {
                timer.cancel();
            }
            
            times--;
        }
        
    }
    View Code
  • 相关阅读:
    记录java设计模式中适配器模式和装饰器模式和代理模式的区别
    excel工具类记录
    docker搭建图床 chevereto 非常方便
    docker 安装mysql
    rabbitmq学习之路(八)
    理解js中的作用域,作用域链以及闭包
    浏览器解析js的顺序
    javacript 组合使用构造函数模式和原型模式
    js垃圾回收机制与深拷贝和浅拷贝
    ES6 变量的解构赋值
  • 原文地址:https://www.cnblogs.com/hezhiyao/p/7637974.html
Copyright © 2011-2022 走看看