[2017.12.02-03]多线程

多线程

1.多线程:如果一个程序的执行路径有多条.
单线程:程序的执行路径只有一条
这里写图片描述

2.面试题:Jvm,java虚拟机是多线程程序吗?
是多线程程序,由于java虚拟机中自带一个垃圾回收器,来确保程序不会轻易的造成内存溢出!
至少开启两条子线程:
当前程序在执行代码的时候,会开启main:主线程
垃圾回收器会开启一个垃圾回收线程,来确保程序不会内存异常,将不用的变量或者没有更多引用的对象来回收掉!

3.演示:

public class ThreadDemo {

    public static void main(String[] args) {

        System.out.println(new Object()) ;
        System.out.println(new Object()) ;
        System.out.println(new Object()) ;
        System.out.println(new Object()) ;

        //....中间创建了很多对象
        System.out.println(new Object()) ;
    }
}

4.重点:如何实现多线程程序?
要实现多线程程序,必须创建一个进程,
创建进程需要调用系统资源进行创建,但是Java语言是不能直接调用系统资源
C/C++语言是可以创建系统资源,然后使用Java语言掉C/C++已经封装好的东西,
Java—->类:Thread类

5.并发和并行
并发:指的是同一个时间点
并行:指的的是一个时间段

6.多线程程序实现方式1:
1)自定一个类:MyThread 继承自Thread类
2)在MyThread类中重写Thread类中的run() :为什么重写run()
3)在主线程中,创建该类的实例对象,启动线程

7.演示:

public class ThreadDemo {

    public static void main(String[] args) {

        //创建该线程的实例对象
//      MyThread my = new MyThread() ;
//      
//      //启动线程
//      /**
//       * 启动线程不是调用run()方法,
//       * strat()是线程开始执行的方法
        //run()方法调用相当于调用了一个普通方法,并不会出现线程随机性;而start()方法调用,
        //其实是通过Jvm调用线程中的run()来进行多个线程抢占CPU执行权
//       */
//      my.start() ;
//      //0java.lang.IllegalThreadStateException
//      /**
//       * 第二次启动线程,会出现:非法线程状态异常
//       * 当前my线程已经启动了,不能重新启动
//       */
//      my.start() ;
//      my.run() ;
//      my.run() ;

        MyThread my1 = new MyThread() ;
        MyThread my2 = new MyThread() ;

        //分别启动线程
        my1.start() ;
        my2.start() ;
    }
}

//自定义一个线程类:MyThread
/**
 * 为什么重写run(),run方法里面执行的耗时的操作.
 * @author Apple
 */
public class MyThread extends Thread {


    /*
     * 重写Thread类中的run()方法
     * */
    @Override
    public void run() {
//      System.out.println("helloworld");
        //耗时的操作,线程睡眠,线程等待,循环语句
        for(int x = 0 ; x <100 ; x ++){
            System.out.println(x);
        }
    }
}

8.如何获取线程的名称?
public final String getName()返回该线程的名称。
设置线程名称
public final void setName(String name)改变线程名称,使之与参数 name 相同。

9.演示:

public class ThreadDemo {

    public static void main(String[] args) {

        //创建线程类的实例
        //无参构造的形式
//      MyThread my1 = new MyThread() ;
//      MyThread my2 = new MyThread() ;


        //有参构造形式设置线程名称
//      MyThread my1 = new MyThread("高圆圆") ;
//      MyThread my2 = new MyThread("张杨") ;

        /*
         * 设置线程名称方式:无参+setName(String name)方法
         * */
        MyThread my1 = new MyThread() ;
        MyThread my2 = new MyThread() ;

        // public final void setName(String name)改变线程名称,使之与参数 name 相同。
        my1.setName("高圆圆") ;
        my2.setName("张杨") ;

        //public static Thread currentThread():表示正在运行的线程
        //默认所有的子线程的都在主线程中
        System.out.println(Thread.currentThread().getName());//main

        //启动线程
        my1.start() ;
        my2.start() ;
    }
}
/*
 * 
 * public class Thread implements Runnable{
 *   private char        name[];
 *  
 * public Thread() {
 *      初始化
        init(null, null, "Thread-" + nextThreadNum(), 0);   //"Thread-" + nextThreadNum()
    }

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }

     private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name.toCharArray();//字符数组
        //此处省略了代码
    }

    rivate static int threadInitNumber;
     private static synchronized(同步机制) int nextThreadNum() {
        return threadInitNumber++;//0,1,2..
    }

    public final String getName() {
        return String.valueOf(name);//将当前name字符数组转换成字符串了
    }
    }
 * 
 * */

public class MyThread extends Thread {



    //无参构造
    public MyThread(){

    }

    //有参构造
    public MyThread(String name){
        super(name) ;
    }
    @Override

    //my1和my2子线程都会执行这段代码,两个子线程在互相抢占CPU的执行权
    public void run() {
        for(int x = 0 ; x <200; x ++){
//          System.out.println(x);
            System.out.println(getName() +":"+x);

        }
    }
}

10.public final int getPriority()返回线程的优先级。
线程的优先级有哪些?
默认优先级:5
java.lang.Thread
public static final int MAX_PRIORITY 10 :最大优先级 优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性!
public static final int MIN_PRIORITY 1 :最小优先级
public static final int NORM_PRIORITY 5 :默认优先级

11.演示:

//测试类
public class ThreadProrityDemo {

    public static void main(String[] args) {

        //创建该线程的实例
        //并且设置线程名称
        MyPriority mp1 = new MyPriority() ;
        MyPriority mp2 = new MyPriority() ;
        MyPriority mp3 = new MyPriority() ;

        //设置线程名称:无参构造+setName()方法

//      //获取线程的优先级
//      System.out.println(mp1.getPriority());//5
//      System.out.println(mp2.getPriority());//5
//      System.out.println(mp3.getPriority());//5

        mp1.setName("张飞") ;
        mp2.setName("刘备") ;
        mp3.setName("关羽") ;

        //给线程设置优先级
        mp1.setPriority(10) ;
        mp2.setPriority(1) ;

        //启动线程
        mp1.start() ;
        mp2.start() ;
        mp3.start() ;
    }
}

//自定义的线程类
public class MyPriority extends Thread {

    @Override
    public void run() {
        for(int x = 0 ; x <100 ; x ++){
            System.out.println(getName()+":"+x);
        }
    }
}

12.public final void join()
throws InterruptedException等待该线程终止。

13.演示:

public class JoinDemo {

    public static void main(String[] args) {

        /*
         * 创建该线程的实例对象
         * */
        JoinThread jt1 = new JoinThread() ;
        JoinThread jt2 = new JoinThread() ;
        JoinThread jt3 = new JoinThread() ;

        //设置线程名称
        jt1.setName("李世民") ;
        jt2.setName("李元霸") ;
        jt3.setName("李渊") ;

        //启动线程


        jt1.start() ;

        //设置线程等待该线程终止该方法必须要启动线程
        try {
            jt1.join() ;
        } catch (InterruptedException e) {
            //InterruptedException:中断异常
            e.printStackTrace();
        }

        jt2.start() ;
        jt3.start() ;
    }
}

14.public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权

15.演示:

public class YieldThreadDemo {

    public static void main(String[] args) {

        //创建线程类对象
        YieldThread yt1 = new YieldThread() ;
        YieldThread yt2 = new YieldThread() ;

        //设置线程名称
        yt1.setName("高圆圆") ;
        yt2.setName("赵又廷") ;

        //启动线程
        yt1.start() ;
        yt2.start() ;
    }
}

/*
 *自定义线程类
 * */
public class YieldThread extends Thread {

        @Override
        public void run() {
            //yt1,yt2
            for(int x =0 ; x <100 ; x ++){
                System.out.println(getName()+":"+x);
                Thread.yield() ;
            }
        }
}

16.线程停止:
public final void stop():强迫线程停止执行
public void interrupt()中断线程。 表示中断线程一种状态

join()
yield()
stop()
setDeamon(boolean on):(用的多)
sleep():线程睡眠 (用的多)
wait():线程等待

17.演示:

public class ThreadStopDemo {

    public static void main(String[] args) {
        //创建线程类对象
        ThreadStop ts = new ThreadStop() ;
        ts.start() ;

        //如果3秒中不醒来,干掉它
        try {
            Thread.sleep(3000) ;
//          ts.stop() ;//该方法表示过时,但是可以用它
            //强迫线程停止执行
            ts.interrupt() ;//中断一种状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

import java.util.Date;

public class ThreadStop extends Thread {

    @Override
    public void run() {
        System.out.println("开始执行了.."+new Date());

        //子线程进来之后,让它睡眠10秒中
        try {
            Thread.sleep(10000) ;
        } catch (InterruptedException e) {
//          e.printStackTrace();
            System.out.println("线程终止了...");
        }

        System.out.println("结束执行"+new Date());
    }
}

18.线程睡眠:
public static void sleep(long millis)
throws InterruptedException在指定的毫秒数内让当前正在执行的线程休眠(暂停执行

19.演示:

public class ThreadSleepDemo {

    public static void main(String[] args) {

        //创建线程类对象
        ThreadSellp ts1 = new ThreadSellp() ;
        ThreadSellp ts2 = new ThreadSellp() ;
        ThreadSellp ts3 = new ThreadSellp() ;

        //设置线程名称
        ts1.setName("线程1") ;
        ts2.setName("线程2") ;
        ts3.setName("线程3") ;

        //启动线程
        ts1.start() ;
        ts2.start() ;
        ts3.start() ;
    }
}

import java.util.Date;

public class ThreadSellp extends Thread {

    @Override
    public void run() {
        //ts1,ts2,ts3
        for(int x = 0 ; x <100 ; x ++){
            System.out.println(getName()+":"+x+",日期:"+new Date());

            //睡眠1秒中:1000毫秒
            try {
                Thread.sleep(1000) ;//此方法本身就抛出一个异常!
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

20.public final void setDaemon(boolean on) on指定true,就是设置守护线程…
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。

jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就自动退出.

比如:坦克大战
坦克大战

21.演示:

public class ThreadDemaonDemo {

    public static void main(String[] args) {

        //创建线程类对象
        ThreadDeamon td1 = new ThreadDeamon() ;
        ThreadDeamon td2 = new ThreadDeamon() ;

        //设置线程名称
        td1.setName("张飞") ;
        td2.setName("关羽") ;

        //setDaemon(boolean on)
        td1.setDaemon(true) ;
        td2.setDaemon(true) ;


        //启动线程
        td1.start() ;
        td2.start() ;

        Thread.currentThread().setName("刘备") ;
        for(int x = 0 ; x <5 ; x++){
            System.out.println(Thread.currentThread().getName()+":"+x); //设置主线程
        }
    }
}

public class ThreadDeamon extends Thread {

        @Override
        public void run() {
            for(int x = 0 ; x <100 ; x ++){
                System.out.println(getName()+":"+x);
            }
        }
}

22.多线程实现的第二种方式:(实际开发中第二种比第一种应用更广泛)
开发步骤:
1)自定义一个类MyRunnable,该类实现Runnable接口
2)实现该接口中的run()方法
3)在主线程中创建该类的实例对象,
4)创建Thread类对象,将3)创建的这个对象作为参数进行传递
5)分别启动线程
这里写图片描述

23.面试题:多线程的实现方式有几种,分别是什么?答三个方式,分别阐述
第三种:和线程池有关系(并且和Callable接口有关系)

24.演示:

public class ThreadDemo {

    public static void main(String[] args) {

        //1)创建MyRunnable实例对象
        MyRunnable my = new MyRunnable() ;

        //2)创建线程类对象
        //Thread线程类中的构造方法
        //public Thread(Runnable target)
//      Thread t1 = new Thread(my) ;
//      t1.setName("线程1") ;
        //public Thread(Runnable target,String name)
        Thread t1 = new Thread(my, "线程1") ;
        Thread t2 = new Thread(my, "线程2") ;

        //启动线程
        t1.start() ;
        t2.start() ;
    }
}

public class MyRunnable implements Runnable {

    @Override
    //run()中的方法也是需要一些耗时的操作
    public void run() {
        for(int x = 0 ; x < 100 ; x ++){
            //在控制台,打印每一个子线程的线程名称
//          System.out.println(getName()+":"+x);
            //getName()是Thread类中的方法
            //间接的使用Thread类的静态功能得到线程名称
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }

}

25.演示:

/*
 * 某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,而它有3个售票窗口售票,请设计一个程序
模拟该电影院售票。
  继承自Thread类
 * */
public class SellTicketDemo {

    public static void main(String[] args) {

        //创建线程类对象
        SellTicket st1 = new SellTicket() ;
        SellTicket st2 = new SellTicket() ;
        SellTicket st3 = new SellTicket() ;

        //分别命名三个窗口
        st1.setName("窗口1") ;
        st2.setName("窗口2") ;
        st3.setName("窗口3") ;

        //启动线程
        st1.start() ;
        st2.start() ;
        st3.start() ;

    }
}

public class SellTicket extends Thread {

    //定义100张票
//  private int tickets = 100 ;

    //这100张票应该被三个线程共用,所以用static修饰
    private static int tickets = 100 ;


    @Override
    public void run() {

        //st1,st2,st3都要执行run()方法中代码
        //有100张票
//      int tickets = 100 ;(将这个代码放到run()方法的外面)

        //模拟该电影院售票:电影院一直有票

        while(true){

            if(tickets>0){
                System.out.println(getName() + "正在出售第" + (tickets--) + "张票");
            }
        }
    }
}

26.演示:

//接口:自定义类实现Runnable接口(研究主要接口的形式)
/*
 * 为了模拟电影院卖票更真实的场景,每一个窗口卖票应该延迟操作
 *  在接口自实现类中,在run()方法中让每一个线程执行睡眠0.1秒
 * 
 *加入延迟操作:
 *      1)一张票可能被卖多次
 *              100张票会出现多次
 *          CPU的执行具有原子性操作
 *      2)可能出现负票
 *          1,0,-1
 *      延迟操作和线程随机性导致
 *
 *
 *这两种情况都属于线程安全问题,现在写的这个代码是一种有问题的代码?
 *  如何解决多线程的安全问题呢?
 *  检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)
 *      1)当前是否是一个多线程环境
 *      2)多线程环境中是否有共享数据
 *      3)是否有多条语句对共享数据进行操作
 *
 *就目前这个电影院卖票这个案例,
 *      1)是多线程环境,因为要实现3个窗口同时卖票
 *      2)有共享数据,比如:tickets
 *      3)有多条语句对当前这个共享数据进行操作
 *      
 *优化改进:
 *  1)多线程环境和共享数据改变不了,突破口就是3)条件:将多条语句对共享数据的操作进行更改
 *  
 *      将多条语句对共享数据进行操作的代码用代码块包起来
 *      Java的同步机制:
 *      使用同步代码块:synchronized(同步锁对象){
 *              多条语句对共享数据的操作;
 *      }
 *
 *同步锁对象:应该每一个线程都要使用这个锁对象(同步锁):理解为门的开和关
 *使用同步代码块可以解决线程安全问题
 *
 *同步锁对象可以是什么样的对象
 *      可以是Object类型,任意的Java类
 * */
public class SellTicketDemo {

    public static void main(String[] args) {

        //创建SellTicket对象
        SellTicket st = new SellTicket() ;

        //创建线程类的对象
        Thread t1 = new Thread(st, "窗口1") ;
        Thread t2 = new Thread(st, "窗口2") ;
        Thread t3 = new Thread(st, "窗口3") ;

        //启动线程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

public class SellTicket implements Runnable {

    //100张票被共用,不让外界修改数据
    private  static int tickets = 100 ;

    //同步锁对象
    private Object obj = new Object() ;

    @Override
    public void run() {

        // 模拟电影院一直有票

        //t1,t2,t3子线程要执行循环语句中的内容
        while (true) {

            //t1线程先抢占CPU的执行权
            //理解为门的开和关
            //t1,t2,t3继续抢占CPU的执行权
            //t2抢占到了,门一关,t1,t3进不来了
            synchronized(obj){//t1进来,门关了,t2和t3线程都不会进来

                if (tickets > 0) {
                    try {
                        Thread.sleep(100) ;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第"
                            + (tickets--) + "张票");
                    //窗口1正在出售第100张
                    //窗口正在出售第99张
                }
            }//代码执行完毕,t1线程出来,意味着门开了...  
            代码执行完毕,t1线程出来,意味着门开了...  


        }
    }

}

27.同步锁定对象:
1)可以Object类型以及任意的Java类型对象
2)如果一个方法进来之后是一个同步代码块,那么同步代码块可以演变成一个同步方法
3)如果是一个静态的同步方法,锁对象是当前类名class属性:类名.class (反射机制:获取一些类的字节码文件对象Class类对象)

28.面试题:思考:
wait()线程等待,notify(),唤醒单个线程,notifyAll():唤醒所有线程这三个方法为什么不定义到Thread类中呢 而是定义在Object类中?
线程中会存在安全问题,并且解决线程安全问题使用的同步代码块或者同步方法来解决,同步代码块来解决线程安全问题,就存在
同步锁对象,谁能代表同步锁对象(Object以及任意的Java类),把它定义到Object类中;等待唤醒机制(生产者和消费者线程)

29.演示:

public class SellTicketDemo {   

public static void main(String[] args) {

    //创建SellTicket对象
    SellTicket st = new SellTicket() ;

    //创建线程类的对象
    Thread t1 = new Thread(st, "窗口1") ;
    Thread t2 = new Thread(st, "窗口2") ;
    Thread t3 = new Thread(st, "窗口3") ;

    //启动线程
    t1.start() ;
    t2.start() ;
    t3.start() ;
}
}

public class SellTicket implements Runnable {

    //100张票被共用,不让外界修改数据
    private  static int tickets = 100 ;

    //同步锁对象
    private Object obj = new Object() ;

    //任意的类的对象
    private Demo d = new Demo() ;

    private int x ;


    //设计模式:单例模式:懒汉式就和线程安全问题有关系

    //Object类型对象
//  @Override
//  public void run() {
//      
//      // 模拟电影院一直有票
//      
//      //t1,t2,t3子线程要执行循环语句中的内容
//      while (true) {
//          
//          //t1线程先抢占CPU的执行权
//          //理解为门的开和关
//          //t1,t2,t3继续抢占CPU的执行权
//          //t2抢占到了,门一关,t1,t3进不来了
//          synchronized(obj){//t1进来,门关了,t2和t3线程都不会进来
//              
//              if (tickets > 0) {
//                  try {
//                      Thread.sleep(100) ;
//                  } catch (InterruptedException e) {
//                      e.printStackTrace();
//                  }
//                  System.out.println(Thread.currentThread().getName() + "正在出售第"
//                          + (tickets--) + "张票");
//                  //窗口1正在出售第100张
//                  //窗口正在出售第99张
//              }
//          }//代码执行完毕,t1线程出来,意味着门开了...  
//          代码执行完毕,t1线程出来,意味着门开了...  
//          
//          
//      }
//  }

    //同步锁对象:任意的自定义类的对象
//  @Override
//  public void run() {
//      
//      // 模拟电影院一直有票
//      
//      //t1,t2,t3子线程要执行循环语句中的内容
//      while (true) {
//          
//          //t1线程先抢占CPU的执行权
//          //理解为门的开和关
//          //t1,t2,t3继续抢占CPU的执行权
//          //t2抢占到了,门一关,t1,t3进不来了
//          synchronized(d){//t1进来,门关了,t2和t3线程都不会进来
//              
//              if (tickets > 0) {
//                  try {
//                      Thread.sleep(100) ;
//                  } catch (InterruptedException e) {
//                      e.printStackTrace();
//                  }
//                  System.out.println(Thread.currentThread().getName() + "正在出售第"
//                          + (tickets--) + "张票");
//                  //窗口1正在出售第100张
//                  //窗口正在出售第99张
//              }
//          }//代码执行完毕,t1线程出来,意味着门开了...  
//          代码执行完毕,t1线程出来,意味着门开了...  
//          
//          
//      }
//  }
    @Override
    public void run() {

        // 模拟电影院一直有票

        //t1,t2,t3子线程要执行循环语句中的内容
        while (true) {
            if(x%2==0){
                synchronized(SellTicket.class){//静态同步方法:要通过反射获取Class类对象(当前类的字节码文件对象)

                    if (tickets > 0) {
                        try {
                            Thread.sleep(100) ;
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第"
                                + (tickets--) + "张票");
                        //窗口1正在出售第100张
                        //窗口正在出售第99张
                    }
                }
            }else{

                sellTicket() ;

            }
            x ++ ;
        }
    }

    //如果一个方法(非静态的方法)进来是一个同步代码块,把这个方法可不可以定义为一个同步方法呢?
//  private void sellTicket() {
//      synchronized (d) {
//
//          if (tickets > 0) {
//              try {
//                  Thread.sleep(100);
//              } catch (InterruptedException e) {
//                  e.printStackTrace();
//              }
//              System.out.println(Thread.currentThread().getName()
//                      + "正在出售第" + (tickets--) + "张票");
//              
//          }
//      }
//  }

    //同步方法 (非静态的同步方法)
    //对于同步方法来说,它的同步锁对象是this
//  public synchronized void sellTicket(){
//      if (tickets > 0) {
//          try {
//              Thread.sleep(100);
//          } catch (InterruptedException e) {
//              e.printStackTrace();
//          }
//          System.out.println(Thread.currentThread().getName()
//                  + "正在出售第" + (tickets--) + "张票");
//          
//      }
//  }

    //如果是静态同步方法,那么同步锁对象是谁呢?
    public static synchronized void sellTicket(){
        if (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()
                    + "正在出售第" + (tickets--) + "张票");

        }
    }

}
class Demo{

}

30.使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况

Jdk5以后Java提供了一个更具体的锁对象:Lock
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
Lock是一个接口,所以它在使用的是 ReentrantLock子实现类

public void lock()获取锁。
public void unlock()试图释放此锁
虽然Jdk5以后提供了具体的锁,但是面试的时候,肯定会问同步机制解决线程安全问题!

31.演示:

public class SellTicketDemo {

    public static void main(String[] args) {

        //创建资源对象
        SellTicket st = new SellTicket() ;

        //创建线程对象
        Thread t1 = new Thread(st, "窗口1") ;
        Thread t2 = new Thread(st, "窗口2") ;
        Thread t3 = new Thread(st, "窗口3") ;

        //启动线程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SellTicket implements Runnable {

    //定义一个100张票
    private int tickets = 100 ;
    //定义锁对象
//  private Object obj = new Object() ;

    //Jdk5以后Java提供了更具的锁定操作:加锁和释放锁
    //定义一个具体锁对象
    private  Lock lock = new ReentrantLock() ;//具体的lock锁

    //捕获异常标准格式:try...catch...finally
    //变形格式:try...finally...
    /**
     * try{
     *  可能出现问题的代码
     * }catch(SocketException e){
     *  //不需要进行处理
     *  //空处理
     * }
     */
    @Override
    public void run() {

        //模拟电影院一直有票
        while(true){
            //同步机制
//          synchronized(obj){

            try{
                //获取锁
                lock.lock() ;
                if(tickets>0){
                    //加入延迟操作
                    try {
                        Thread.sleep(100) ;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
                }
            }finally{
                //试图释放锁对象
                lock.unlock() ;
            }

//          }

        }
    }

}

32.使用同步机制可以解决多线程的安全问题,但是自身也会有弊端:
1)同步—->执行效率低(每一个线程在抢占到CPU的执行权,会去将(门)关闭,别的线程进不来)
2)容易出现死锁现象
死锁线程:两个或者两个以上的线程出现了互相等待的情况,就会出现死锁!

举例:
中国人和美国人吃饭
中国人:一双筷子
美国人:一把刀,一把叉

现在:
中国人:一根筷子和一把刀
美国人:一根筷子和一把叉

线程通信的问题:使用消费者和生产者模式

33.演示:

public class DieLockDemo {

    public static void main(String[] args) {

        //创建线程类对象
        DieLock dl1 = new DieLock(true) ;
        DieLock dl2 = new DieLock(false);

        //启动线程
        dl1.start() ;
        dl2.start() ;
    }

    //if objA   else objB
    //else objB if objA
    /**
     * 理想状态
     * if objA
       if objB
       else objB
        else objA
     */
}

public class DieLock extends Thread {

    //定义一个成员变量
    private boolean flag ;

    public DieLock(boolean flag){
        this.flag = flag ;
    }

    //重写run()方法

    @Override
    public void run() {
        //dl1,dl2线程
        if(flag){
            synchronized(MyLock.objA){
                System.out.println("if objA");
                synchronized (MyLock.objB) {
                    System.out.println("if objB");
                }
            }//代码执行完毕,objA锁相当于才能被释放掉
        }else {
            //dl2
            synchronized (MyLock.objB) {
                System.out.println("else objB");
                synchronized(MyLock.objA){
                    System.out.println("else objA");
                }
            }
        }

    }
}

public class MyLock {
    //创建两把锁对象
    public static final Object objA = new Object() ;
    public static final Object objB = new Object() ;
}

34.演示:

/**
 * 分析:
 *      提供:资源对象:Student类      提供一些成员变量:姓名 和年龄
 *          生产者线程:SetThread类:  生产一些学生数据(设置学生数据)
 *          消费者线程:GetThread类:  输出学生数据
 *          测试类:StudentDemo类,实现多线程环境
 *
 *使用刚才的这几个类:模拟生产消费者模式,生产者SetThread产生学生数据,而GetThread消费者线程输出学生数据,发现一个问题,
 *问题:
 *      输出学生数据的时候,是null--0
 *
 *      对于每一个线程都在创建自己的学生对象,两个线程操作的两个对象而不是同一个对象,所以应该解决:
 *      将学生对象成员变量,然后通过构造方法进行传递,在测试类中,创建学生对象(同一个资源对象)让多个线程对这个学生对象进行操作
 *
 *
 *改进:为了数据多并且效果更明显,加入循环语句进行操作,给生产者线程和消费者线程分别加入循环语句(while循环)
 */
public class StudentDemo {


    public static void main(String[] args) {

        //创建一个资源对象
        Student s = new Student() ;

        //创建资源对象
        SetThread st = new SetThread(s) ;
        GetThread gt = new GetThread(s) ;

        //创建线程类对象
        Thread t1 = new Thread(st) ;
        Thread t2 = new Thread(gt) ;

        //分别启动线程

        t1.start() ;
        t2.start() ;

    }
}


//生产者线程
public class SetThread implements Runnable {

    private Student s ;
    public SetThread(Student s){
        this.s = s ;
    }
    @Override
    public void run() {

        //设置学生数据
        s.name = "高圆圆" ;
        s.age = 27 ;
    }

}

//消费者线程
public class GetThread implements Runnable {

    private Student s ;
    public GetThread(Student s){
        this.s = s ;
    }
    @Override
    public void run() {
        //输出语句
        System.out.println(s.name+"---"+s.age);
    }

}

public class Student {

    String name;
    int age ;


}

35.演示:

/**
 * 分析:
 *      提供:资源对象:Student类      提供一些成员变量:姓名 和年龄
 *          生产者线程:SetThread类:  生产一些学生数据(设置学生数据)
 *          消费者线程:GetThread类:  输出学生数据
 *          测试类:StudentDemo类,实现多线程环境
 *
 *使用刚才的这几个类:模拟生产消费者模式,生产者SetThread产生学生数据,而GetThread消费者线程输出学生数据,发现一个问题,
 *问题:
 *      输出学生数据的时候,是null--0
 *
 *      对于每一个线程都在创建自己的学生对象,两个线程操作的两个对象而不是同一个对象,所以应该解决:
 *      将学生对象成员变量,然后通过构造方法进行传递,在测试类中,创建学生对象(同一个资源对象)让多个线程对这个学生对象进行操作
 *
 *
 *改进:为了数据多并且效果更明显,加入循环语句进行操作,给生产者线程和消费者线程分别加入循环语句(while循环)
 *  改进之后出现两个问题:
 *      1)同一个数据打印多次
 *      //CPU一点点时间片足够执行很多次
 *      2)并且年龄和姓名不符合
 *          线程的随机性导致的
 *
 *优化改进之后,这些问题就说明当前多线程有安全问题:
 *      多线程安全问题的标准:
 *          1)是否是多线程环境
 *          2)是否有共享数据
 *          3)是否有多条语句对共享数据操作
 *
 *      当前是多线程环境
 *          有共享数据
 *          有多条语句对共享数据:s.name,s.age
 *使用同步机制来解决这个问题:将多条语句对共享数据进包装
 *
 *使用同步机制去解决线程的安全问题,但是又有一个新的问题:
 *      测试的时候,数据打印一打一大片,体验不好!
 *需求:
 *      让这个数据依次进行打印控制台,要使用这种方式去解决,利用Java等待唤醒机制
 *
 *          
 */
public class StudentDemo {


    public static void main(String[] args) {

        //创建一个资源对象
        Student s = new Student() ;

        //创建资源对象
        SetThread st = new SetThread(s) ;
        GetThread gt = new GetThread(s) ;

        //创建线程类对象
        Thread t1 = new Thread(st) ;
        Thread t2 = new Thread(gt) ;

        //分别启动线程

        t1.start() ;
        t2.start() ;

    }
}

//生产者线程
public class SetThread implements Runnable {

    private Student s ;
    public SetThread(Student s){
        this.s = s ;
    }

    private int x = 0 ;
    @Override
    public void run() {

        while(true){
            //同步机制进行操作
            synchronized (s) {
                if(x%2==0){
                    //x = 0 
                    //设置学生数据
                    s.name = "高圆圆" ; //记录name的值是高圆圆
                    s.age = 38 ;
                }else{

                    //设置学生数据
                    s.name = "张杨" ;
                    s.age = 27 ; //age = 27 ;
                }
                x ++ ;//1
            }


        }

    }

}

//消费者线程
public class GetThread implements Runnable {

    private Student s ;
    public GetThread(Student s){
        this.s = s ;
    }
    @Override
    public void run() {
        while(true){
            synchronized (s) {
                //输出语句
                //高圆圆
                System.out.println(s.name+"---"+s.age);
                //高圆圆--27
                //高圆圆-27
            }


        }

    }

}


public class Student {

    String name;
    int age ;


}

36.演示:

/**
 * 分析:
 *      提供:资源对象:Student类      提供一些成员变量:姓名 和年龄
 *          生产者线程:SetThread类:  生产一些学生数据(设置学生数据)
 *          消费者线程:GetThread类:  输出学生数据
 *          测试类:StudentDemo类,实现多线程环境
 *
 *使用刚才的这几个类:模拟生产消费者模式,生产者SetThread产生学生数据,而GetThread消费者线程输出学生数据,发现一个问题,
 *问题:
 *      输出学生数据的时候,是null--0
 *
 *      对于每一个线程都在创建自己的学生对象,两个线程操作的两个对象而不是同一个对象,所以应该解决:
 *      将学生对象成员变量,然后通过构造方法进行传递,在测试类中,创建学生对象(同一个资源对象)让多个线程对这个学生对象进行操作
 *
 *
 *改进:为了数据多并且效果更明显,加入循环语句进行操作,给生产者线程和消费者线程分别加入循环语句(while循环)
 *  改进之后出现两个问题:
 *      1)同一个数据打印多次
 *      //CPU一点点时间片足够执行很多次
 *      2)并且年龄和姓名不符合
 *          线程的随机性导致的
 *
 *优化改进之后,这些问题就说明当前多线程有安全问题:
 *      多线程安全问题的标准:
 *          1)是否是多线程环境
 *          2)是否有共享数据
 *          3)是否有多条语句对共享数据操作
 *
 *      当前是多线程环境
 *          有共享数据
 *          有多条语句对共享数据:s.name,s.age
 *使用同步机制来解决这个问题:将多条语句对共享数据进包装
 *
 *使用同步机制去解决线程的安全问题,但是又有一个新的问题:
 *      测试的时候,数据打印一打一大片,体验不好!
 *需求:
 *      让这个数据依次进行打印控制台,要使用这种方式去解决,利用Java等待唤醒机制
 *
 *          
 */
public class StudentDemo {


    public static void main(String[] args) {

        //创建一个资源对象
        Student s = new Student() ;

        //创建资源对象
        SetThread st = new SetThread(s) ;
        GetThread gt = new GetThread(s) ;

        //创建线程类对象
        Thread t1 = new Thread(st) ;
        Thread t2 = new Thread(gt) ;

        //分别启动线程

        t1.start() ;
        t2.start() ;

    }
}

//生产者线程
public class SetThread implements Runnable {

    private Student s ;
    public SetThread(Student s){
        this.s = s ;
    }

    private int x = 0 ;
    @Override
    public void run() {

        while(true){
            //同步机制进行操作
            synchronized (s) {
                //判断有没有数据
                if(s.flag){
                    //处于等待状态
                    try {
                        s.wait() ;//阻塞式方法,立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(x%2==0){
                    //x = 0 
                    //设置学生数据
                    s.name = "高圆圆" ; //记录name的值是高圆圆
                    s.age = 38 ;
                }else{

                    //设置学生数据
                    s.name = "张杨" ;
                    s.age = 27 ; //age = 27 ;
                }
                x ++ ;//1


                //修改标记
                s.flag = true ;//有数据了
                //通知t2:消费者线程来消费数据
                s.notify() ;//唤醒等待这种状态...
            }




        }

    }

}

//消费者线程
public class GetThread implements Runnable {

    private Student s ;
    public GetThread(Student s){
        this.s = s ;
    }
    @Override
    public void run() {
        while(true){
            synchronized (s) {
                //判断有没有数据
                if(!s.flag){
                    try {
                        s.wait() ;//调用的时候,会立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //输出语句
                //高圆圆
                System.out.println(s.name+"---"+s.age);
                //高圆圆--27
                //高圆圆-27

                //修改标记
                s.flag = false ;//消费者线程
                //通知对方(t1线程),消费者线程没有数据类,赶紧来消费
                s.notify() ;//唤醒t1线程....
            }



        }

    }

}

public class Student {

    String name;
    int age ;
    //声明一个变量
    boolean flag ; //默认没有数据,如果true,则说明有数据


}

37.线程组表示一个线程的集合:Java允许一个线程中有多个线程

38.演示:

public class ThreadGroupDemo {

    public static void main(String[] args) {
//      method1() ;

        method2() ;
    }


    //给每一个子线程可以设置线程名称
    private static void method2() {
        //如何设置线程组名称呢?
//      public ThreadGroup(String name)构造一个新线程组
        ThreadGroup tg = new ThreadGroup("这是一个新的线程组") ;
        //创建线程类对象,并且将线程组对象作为参数进行传递,就使用Thread类的构造方法
        //public Thread(ThreadGroup group,Runnable target ,String name){}
        //创建资源对象
        MyRunnable my = new MyRunnable() ;
        Thread t1 = new Thread(tg, my, "线程1") ;
        Thread t2 = new Thread(tg, my, "线程2") ;

        ThreadGroup tg1 = t1.getThreadGroup() ;
        ThreadGroup tg2 = t2.getThreadGroup() ;

        System.out.println(tg1.getName());
        System.out.println(tg2.getName());

        tg.setDaemon(true) ;//将线程组中的所有的线程都设置为守护线程(后台线程)
    }

    private static void method1() {
        //如何获取多个线程所在的线程组名称呢?
        //创建资源对象
        MyRunnable my = new MyRunnable() ;
        //创建线程类对象
        Thread t1 = new Thread(my) ;
        Thread t2 = new Thread(my) ;

        //启动线程
//      t1.start() ;
//      t2.start() ;

        //获取t1,和t2线程所在的线程名称?
        //获取线程组对象
//      public final ThreadGroup getThreadGroup()返回该线程所属的线程组
        ThreadGroup tg1 = t1.getThreadGroup() ;
        ThreadGroup tg2 = t2.getThreadGroup() ;

        //public final ThreadGroup getThreadGroup()返回该线程所属的线程组
        String name1 = tg1.getName() ;
        String name2 = tg2.getName() ;

        //子线程默认的线程组名称:main线程
        System.out.println(name1);
        System.out.println(name2);
        //所有的线程它的默认线程组名称就是main
        System.out.println(Thread.currentThread().getThreadGroup().getName());


    }
}

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        for(int x = 0 ; x <100 ; x ++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }

    }

}

39.演示:

/**
 * 分析:
 *      提供:资源对象:Student类      提供一些成员变量:姓名 和年龄
 *          生产者线程:SetThread类:  生产一些学生数据(设置学生数据)
 *          消费者线程:GetThread类:  输出学生数据
 *          测试类:StudentDemo类,实现多线程环境
 *
 *使用刚才的这几个类:模拟生产消费者模式,生产者SetThread产生学生数据,而GetThread消费者线程输出学生数据,发现一个问题,
 *问题:
 *      输出学生数据的时候,是null--0
 *
 *      对于每一个线程都在创建自己的学生对象,两个线程操作的两个对象而不是同一个对象,所以应该解决:
 *      将学生对象成员变量,然后通过构造方法进行传递,在测试类中,创建学生对象(同一个资源对象)让多个线程对这个学生对象进行操作
 *
 *
 *改进:为了数据多并且效果更明显,加入循环语句进行操作,给生产者线程和消费者线程分别加入循环语句(while循环)
 *  改进之后出现两个问题:
 *      1)同一个数据打印多次
 *      //CPU一点点时间片足够执行很多次
 *      2)并且年龄和姓名不符合
 *          线程的随机性导致的
 *
 *优化改进之后,这些问题就说明当前多线程有安全问题:
 *      多线程安全问题的标准:
 *          1)是否是多线程环境
 *          2)是否有共享数据
 *          3)是否有多条语句对共享数据操作
 *
 *      当前是多线程环境
 *          有共享数据
 *          有多条语句对共享数据:s.name,s.age
 *使用同步机制来解决这个问题:将多条语句对共享数据进包装
 *
 *使用同步机制去解决线程的安全问题,但是又有一个新的问题:
 *      测试的时候,数据打印一打一大片,体验不好!
 *需求:
 *      让这个数据依次进行打印控制台,要使用这种方式去解决,利用Java等待唤醒机制
 *
 *
 *再次改进:(最终版代码)
 *      现在将资源对象Student中的成员变量私有化
 *      并且给当前类中提供两个方法,同步方法
 *      在两个线程:生产者线程和消费者中线程,注意调用这两个方法就可以了!
 *
 *          
 */
public class StudentDemo {


    public static void main(String[] args) {

        //创建一个资源对象
        Student s = new Student() ;

        //创建资源对象
        SetThread st = new SetThread(s) ;
        GetThread gt = new GetThread(s) ;

        //创建线程类对象
        Thread t1 = new Thread(st) ;
        Thread t2 = new Thread(gt) ;

        //分别启动线程

        t1.start() ;
        t2.start() ;

    }
}

//生产者线程
public class SetThread implements Runnable {

    private Student s ;
    public SetThread(Student s){
        this.s = s ;
    }

    private int x = 0 ;
    @Override
    public void run() {
        while(true){
            if(x %2 ==0){
                s.set("高圆圆", 38) ;
            }else{
                s.set("张杨", 27) ;
            }
            x ++ ;
        }

    }

}

//消费者线程
public class GetThread implements Runnable {

    private Student s ;
    public GetThread(Student s){
        this.s = s ;
    }
    @Override
    public void run() {
        while (true) {

            // 调用方法
            s.get();
        }

    }


}

public class Student {

    private String name;
    private int age ;
    //声明一个变量
    private boolean flag ; //默认没有数据,如果true,则说明有数据


    //set(String name,int age)方法,产生数据数据
    public synchronized void set(String name, int age) {
        // 同步机制进行操作
        // 判断有没有数据
        if (this.flag) {
            // 处于等待状态
            try {
                this.wait();// 阻塞式方法,立即释放锁 notify notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //设置学生数据
        this.name = name ;
        this.age = age ;

        //修改标记
        this.flag = true ;//有数据了
        //通知t2:消费者线程来消费数据
        this.notify() ;//唤醒等待这种状态...
    }

    public synchronized void get(){
            if(!this.flag){
                try {
                    this.wait() ;//调用的时候,会立即释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //输出语句
            //高圆圆
            System.out.println(this.name+"---"+this.age);


            //修改标记
            this.flag = false ;//消费者线程
            //通知对方(t1线程),消费者线程没有数据类,赶紧来消费
            this.notify() ;//唤醒t1线程....
    }

}

40.线程池的好处:节约成本,很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用!

JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnabl e对象或者Callable对象代表的线程。它提供了如下方法
ExecutorsService :接口中的方法
Future

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorsDemo {

    public static void main(String[] args) {

        //创建线程池对象,使用Executors工厂类
//      public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService pool = Executors.newFixedThreadPool(2) ;

        //下来使用ExecutorService(跟踪多个异步任务)一些方法

        //使用submit(Runnable target):提交多个任务
        pool.submit(new MyRunnable()) ;
        pool.submit(new MyRunnable()) ;

        //结束线程池
//      void shutdown()
        pool.shutdown() ;


    }
}

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        //for循环
        for(int x = 0 ; x < 100 ; x ++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }

}

42.多线程程序的实现方式3:(实际开发中很少用到!)
public static ExecutorService newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnabl e对象或者Callable对象代表的线程。它提供了如下方法

ExecutorsService :接口中的方法
Future submit(Callable task)
该返回值表示:异步计算的结果!

43.演示:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CallableDemo {

    public static void main(String[] args) {

        //创建线程池对象,利用工厂类
        ExecutorService Threadpool = Executors.newFixedThreadPool(2) ;

        //提交Callable任务(异步任务)
        Threadpool.submit(new MyCallable()) ;//相当于线程中的start()方法
        Threadpool.submit(new MyCallable()) ;

        //结束线程池
        Threadpool.shutdown() ;
    }
}

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Object> {


    //call()方法的返回值是和Callable中的泛型是一致的!
    @Override
    public Object call() throws Exception {

        for(int x = 0 ; x < 100 ; x ++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
        return null;

    }

}

44.演示:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableDemo {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        //创建线程池对象,利用工厂类:Executors
        ExecutorService ThreadPool = Executors.newFixedThreadPool(2) ;

        //提交2异步任务,分别计算1-100,1-200之间的和
        Future<Integer> f1 = ThreadPool.submit(new MyCallable(100)) ;
        Future<Integer> f2 = ThreadPool.submit(new MyCallable(200)) ;

        //分别调用Future接口中  get()方法,返回具体的结果
        Integer v1 = f1.get() ;
        Integer v2 = f2.get() ;

        //输出结果
        System.out.println("v1:"+v1);
        System.out.println("v2:"+v2);
    }
}

import java.util.concurrent.Callable;

//线程求和
public class MyCallable implements Callable<Integer> {

    private int number ;
    public MyCallable(int number){
        this.number = number ;
    }

    @Override
    public Integer call() throws Exception {
        //定义最终结果变量
        int sum = 0 ;
        for(int x = 1 ; x <=number;  x ++ ){
            sum += x ;
        }
        return sum;
    }


}

45.JavaSe中的定时器: Timer:

常用的几个方法:
public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
public void schedule(TimerTask task, long delay, long period)
在多少毫秒后,执行任务,并且每个多少毫秒重复执行
public void cancel()终止此计时器,丢弃所有当前已安排的任务

46.演示:
需求:3秒后执行爆炸任务

import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {

    public static void main(String[] args) {
        //public Timer()创建一个新计时器。

        Timer t = new Timer() ;

        //调用public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
        //TimerTask:需要被执行的任务类是一个抽象类,所以不能直接实例化
        t.schedule(new MyTask(t), 3000) ;
    }
}

//定义一个任务类:MyTask
//TimerTask中的一个抽象方法:public abstract void run():执行定时器的任务
class MyTask extends TimerTask{

    private Timer t ;

    public MyTask(){

    }

    public MyTask(Timer t){
        this.t = t ;
    }

    @Override
    public void run() {
        System.out.println("bom,爆炸了...");
        t.cancel() ;//取消任务...
    }

}

import java.util.Timer;
import java.util.TimerTask;

/**
 * public void schedule(TimerTask task, long delay, long period)
 *              在多少毫秒后,执行任务,并且每个多少毫秒重复执行
 * 需求:3秒后执行爆炸任务,每隔2秒重复爆炸
 */
public class TimerDemo2 {

    public static void main(String[] args) {
        //创建定时器对象
        Timer t = new Timer() ;


        //调用方法
        t.schedule(new MyTask2(), 3000, 2000) ;
    }
}

class MyTask2 extends TimerTask {

    @Override
    public void run() {
        System.out.println("bom,爆炸了....");
    }

}

46.演示:

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
 */
//删除的demo文件夹的任务
class DeleteFolder extends TimerTask{

    @Override
    public void run() {
        //封装当前项目下的这个demo文件
        File srcFolder = new File("demo") ;
        deleteFolder(srcFolder) ;
    }

    //递归删除
    private void deleteFolder(File srcFolder) {
        //获取当前srcFolder下面的所有的文件以及文件夹的File数组
        File[] fileArray = srcFolder.listFiles() ;
        //对该对象非空判断
        if(fileArray !=null){
            //增强for遍历
            for(File file :fileArray){
                //继续判断file对象是否是文件夹
                if(file.isDirectory()){
                    //继续回到删除目录的方法
                    deleteFolder(file) ;
                }else{
                    //不是目录,是文件,直接删除
                    System.out.println(file.getName()+"---"+file.delete());
                }
            }
            System.out.println(srcFolder.getName()+"----"+srcFolder.delete());
        }
    }

}
public class TimerTest {


    public static void main(String[] args) throws ParseException {

        //创建一个定时器对象
        Timer t = new  Timer() ;

        //public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务

        //定义一个文本日期格式
        String dateStr = "2017-12-3 15:50:00" ;
        //解析成Date对象
        //创建SimpleDateFormat对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
        //解析方法
        Date date = sdf.parse(dateStr) ;
        //调用定时器的这个在规定时间内执行某个任务的方法
        t.schedule(new DeleteFolder(), date) ;
    }
}

47.演示:

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
 */
//删除的demo文件夹的任务
class DeleteFolder extends TimerTask{

    @Override
    public void run() {
        //封装当前项目下的这个demo文件
        File srcFolder = new File("demo") ;
        deleteFolder(srcFolder) ;
    }

    //递归删除
    private void deleteFolder(File srcFolder) {
        //获取当前srcFolder下面的所有的文件以及文件夹的File数组
        File[] fileArray = srcFolder.listFiles() ;
        //对该对象非空判断
        if(fileArray !=null){
            //增强for遍历
            for(File file :fileArray){
                //继续判断file对象是否是文件夹
                if(file.isDirectory()){
                    //继续回到删除目录的方法
                    deleteFolder(file) ;
                }else{
                    //不是目录,是文件,直接删除
                    System.out.println(file.getName()+"---"+file.delete());
                }
            }
            System.out.println(srcFolder.getName()+"----"+srcFolder.delete());
        }
    }

}
public class TimerTest {


    public static void main(String[] args) throws ParseException {

        //创建一个定时器对象
        Timer t = new  Timer() ;

        //public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务

        //定义一个文本日期格式
        String dateStr = "2017-12-3 15:50:00" ;
        //解析成Date对象
        //创建SimpleDateFormat对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
        //解析方法
        Date date = sdf.parse(dateStr) ;
        //调用定时器的这个在规定时间内执行某个任务的方法
        t.schedule(new DeleteFolder(), date) ;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值