• 多线程


    * 进程:
    * 正在运行的程序,是系统进行资源分配和调用的独立单位。
    * 每一个进程都有它自己的内存空间和系统资源。
    * 线程:
    * 是进程中的单个顺序控制流,是一条执行路径
    * 一个进程如果只有一条执行路径,则称为单线程程序。
    * 一个进程如果有多条执行路径,则称为多线程程序。

    *
    * 大家注意两个词汇的区别:并行和并发。
    * 前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。
    * 后者是物理上同时发生,指在某一个时间点同时运行多个程序。
    *
    * Java程序的运行原理:
    * 由java命令启动JVM,JVM启动就相当于启动了一个进程。
    * 接着有该进程创建了一个主线程去调用main方法。
    *
    * 思考题:
    * jvm虚拟机的启动是单线程的还是多线程的?
    * 多线程的。
    * 原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。
    * 现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。

    * 方式1:继承Thread类。
    * 步骤
    * A:自定义类MyThread继承Thread类。
    * B:MyThread类里面重写run()?
    * 为什么是run()方法呢?
    * C:创建对象
    * D:启动线程

     1 /*
     2  * 该类要重写run()方法,为什么呢?
     3  * 不是类中的所有代码都需要被线程执行的。
     4  * 而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
     5  */
     6 public class MyThread extends Thread {
     7 
     8     @Override
     9     public void run() {
    10         // 自己写代码
    11         // System.out.println("好好学习,天天向上");
    12         // 一般来说,被线程执行的代码肯定是比较耗时的。所以我们用循环改进
    13         for (int x = 0; x < 200; x++) {
    14             System.out.println(x);
    15         }
    16     }
    17 }

    // 调用run()方法为什么是单线程的呢?
    // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果
    // 要想看到多线程的效果,就必须说说另一个方法:start()
    // 面试题:run()和start()的区别?
    // run():仅仅是封装被线程执行的代码,直接调用是普通方法
    // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。

    // MyThread my = new MyThread();
    // my.start();
    // // IllegalThreadStateException:非法的线程状态异常
    // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
    // my.start();

    1         // 创建两个线程对象
    2         MyThread my1 = new MyThread();
    3         MyThread my2 = new MyThread();
    4 
    5         my1.start();
    6         my2.start();

    * 如何获取线程对象的名称呢?
    * public final String getName():获取线程的名称。
    * 如何设置线程对象的名称呢?
    * public final void setName(String name):设置线程的名称
    *
    * 针对不是Thread类的子类中如何获取线程对象名称呢?
    * public static Thread currentThread():返回当前正在执行的线程对象
    * Thread.currentThread().getName()

    方法一:

    1         // 创建线程对象
    2         //无参构造+setXxx()
    3          MyThread my1 = new MyThread();
    4          MyThread my2 = new MyThread();
    5         // //调用方法设置名称
    6          my1.setName("林青霞");
    7          my2.setName("刘意");
    8          my1.start();
    9          my2.start();

    方法二:

     1         //带参构造方法给线程起名字
     2          MyThread my1 = new MyThread("林青霞");
     3          MyThread my2 = new MyThread("刘意");
     4          my1.start();
     5          my2.start();
     6         
     7         //我要获取main方法所在的线程对象的名称,该怎么办呢?
     8         //遇到这种情况,Thread类提供了一个很好玩的方法:
     9         //public static Thread currentThread():返回当前正在执行的线程对象
    10         System.out.println(Thread.currentThread().getName());
     1 public class MyThread extends Thread {
     2 
     3     public MyThread() {
     4     }
     5     
     6     public MyThread(String name){
     7         super(name);
     8     }
     9 
    10     @Override
    11     public void run() {
    12         for (int x = 0; x < 100; x++) {
    13             System.out.println(getName() + ":" + x);
    14         }
    15     }
    16 }

    * 我们的线程没有设置优先级,肯定有默认优先级。
    * 那么,默认优先级是多少呢?
    * 如何获取线程对象的优先级?
    * public final int getPriority():返回线程对象的优先级
    * 如何设置线程对象的优先级呢?
    * public final void setPriority(int newPriority):更改线程的优先级。
    *
    * 注意:
    * 线程默认优先级是5。
    * 线程优先级的范围是:1-10。
    * 线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。
    *
    * IllegalArgumentException:非法参数异常。
    * 抛出的异常表明向方法传递了一个不合法或不正确的参数。

     1         ThreadPriority tp1 = new ThreadPriority();
     2         ThreadPriority tp2 = new ThreadPriority();
     3         ThreadPriority tp3 = new ThreadPriority();
     4 
     5         tp1.setName("东方不败");
     6         tp2.setName("岳不群");
     7         tp3.setName("林平之");
     8 
     9         // 获取默认优先级
    10         // System.out.println(tp1.getPriority());
    11         // System.out.println(tp2.getPriority());
    12         // System.out.println(tp3.getPriority());
    13 
    14         // 设置线程优先级
    15         // tp1.setPriority(100000);
    16         
    17         //设置正确的线程优先级
    18         tp1.setPriority(10);
    19         tp2.setPriority(1);
    20 
    21         tp1.start();
    22         tp2.start();
    23         tp3.start();

    * 线程休眠
    * public static void sleep(long millis)

     * public final void join():等待该线程终止。 

    等线程tj1执行完毕才执行其他线程

     1         ThreadJoin tj1 = new ThreadJoin();
     2         ThreadJoin tj2 = new ThreadJoin();
     3         ThreadJoin tj3 = new ThreadJoin();
     4 
     5         tj1.setName("李渊");
     6         tj2.setName("李世民");
     7         tj3.setName("李元霸");
     8 
     9         tj1.start();
    10         try {
    11             tj1.join();
    12         } catch (InterruptedException e) {
    13             e.printStackTrace();
    14         }
    15         
    16         tj2.start();
    17         tj3.start();

    * public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
    * 让多个线程的执行更和谐,但是不能靠它保证一人一次。

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

     1     public static void main(String[] args) {
     2         ThreadDaemon td1 = new ThreadDaemon();
     3         ThreadDaemon td2 = new ThreadDaemon();
     4 
     5         td1.setName("关羽");
     6         td2.setName("张飞");
     7 
     8         // 设置收获线程
     9         td1.setDaemon(true);
    10         td2.setDaemon(true);
    11 
    12         td1.start();
    13         td2.start();
    14 
    15         Thread.currentThread().setName("刘备");
    16         for (int x = 0; x < 5; x++) {
    17             System.out.println(Thread.currentThread().getName() + ":" + x);
    18         }
    19     }

    * public final void stop():让线程停止,过时了,但是还可以使用。
    * public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。

    线程的生命周期:

    * 方式2:实现Runnable接口
    * 步骤:
    * A:自定义类MyRunnable实现Runnable接口
    * B:重写run()方法
    * C:创建MyRunnable类的对象
    * D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

     1 public class MyRunnable implements Runnable {
     2 
     3     @Override
     4     public void run() {
     5         for (int x = 0; x < 100; x++) {
     6             // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
     7             System.out.println(Thread.currentThread().getName() + ":" + x);
     8         }
     9     }
    10 
    11 }
     1     public static void main(String[] args) {
     2         // 创建MyRunnable类的对象
     3         MyRunnable my = new MyRunnable();
     4 
     5         // 创建Thread类的对象,并把C步骤的对象作为构造参数传递
     6         // Thread(Runnable target)
     7         // Thread t1 = new Thread(my);
     8         // Thread t2 = new Thread(my);
     9         // t1.setName("林青霞");
    10         // t2.setName("刘意");
    11 
    12         // Thread(Runnable target, String name)
    13         Thread t1 = new Thread(my, "林青霞");
    14         Thread t2 = new Thread(my, "刘意");
    15 
    16         t1.start();
    17         t2.start();
    18     }

    多线程两种方式的图解比较和区别:

    * 实现Runnable接口的方式实现
    *
    * 通过加入延迟后,就产生了连个问题:
    * A:相同的票卖了多次
    * CPU的一次操作必须是原子性的
    * B:出现了负数票
    * 随机性和延迟导致的

    * 思想:
    * 把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
    * 问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。
    *
    * 同步代码块:
    * synchronized(对象){
    * 需要同步的代码;
    * }
    *
    * A:对象是什么呢?
    * 我们可以随便创建一个对象试试。
    * B:需要同步的代码是哪些呢?
    * 把多条语句操作共享数据的代码的部分给包起来
    *
    * 注意:
    * 同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
    * 多个线程必须是同一把锁。

     1     // 定义100张票
     2     private int tickets = 100;
     3 
     4     // 定义同一把锁
     5     private Object obj = new Object();
     6 
     7     @Override
     8     public void run() {
     9         while (true) {
    10             // t1,t2,t3都能走到这里
    11             // 假设t1抢到CPU的执行权,t1就要进来
    12             // 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去。所以就等着。
    13             // 门(开,关)
    14             synchronized (obj) { // 发现这里的代码将来是会被锁上的,所以t1进来后,就锁了。(关)
    15                 if (tickets > 0) {
    16                     try {
    17                         Thread.sleep(100); // t1就睡眠了
    18                     } catch (InterruptedException e) {
    19                         e.printStackTrace();
    20                     }
    21                     System.out.println(Thread.currentThread().getName()
    22                             + "正在出售第" + (tickets--) + "张票 ");
    23                     //窗口1正在出售第100张票
    24                 }
    25             } //t1就出来可,然后就开门。(开)
    26         }
    27     }

    * 同步的特点:
    * 前提:
    * 多个线程
    * 解决问题的时候要注意:
    * 多个线程使用的是同一个锁对象
    * 同步的好处
    * 同步的出现解决了多线程的安全问题。
    * 同步的弊端
    * 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

    * A:同步代码块的锁对象是谁呢?
    * 任意对象。
    *
    * B:同步方法的格式及锁对象问题?
    * 把同步关键字加在方法上。
    *
    * 同步方法是谁呢?
    * this
    *
    * C:静态方法及锁对象问题?
    * 静态方法的锁对象是谁呢?
    * 类的字节码文件对象。

     1         // 线程安全的类
     2         StringBuffer sb = new StringBuffer();
     3         Vector<String> v = new Vector<String>();
     4         Hashtable<String, String> h = new Hashtable<String, String>();
     5 
     6         // Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你
     7         // 那么到底用谁呢?
     8         // public static <T> List<T> synchronizedList(List<T> list)
     9         List<String> list1 = new ArrayList<String>();// 线程不安全
    10         List<String> list2 = Collections
    11                 .synchronizedList(new ArrayList<String>()); // 线程安全

    * 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
    * 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
    *
    * Lock:
    * void lock(): 获取锁。
    * void unlock():释放锁。
    * ReentrantLock是Lock的实现类.

     1 public class SellTicket implements Runnable {
     2 
     3     // 定义票
     4     private int tickets = 100;
     5 
     6     // 定义锁对象
     7     private Lock lock = new ReentrantLock();
     8 
     9     @Override
    10     public void run() {
    11         while (true) {
    12             try {
    13                 // 加锁
    14                 lock.lock();
    15                 if (tickets > 0) {
    16                     try {
    17                         Thread.sleep(100);
    18                     } catch (InterruptedException e) {
    19                         e.printStackTrace();
    20                     }
    21                     System.out.println(Thread.currentThread().getName()
    22                             + "正在出售第" + (tickets--) + "张票");
    23                 }
    24             } finally {
    25                 // 释放锁
    26                 lock.unlock();
    27             }
    28         }
    29     }
    30 
    31 }

    死锁:

     1 public class DieLock extends Thread {
     2 
     3     private boolean flag;
     4 
     5     public DieLock(boolean flag) {
     6         this.flag = flag;
     7     }
     8 
     9     @Override
    10     public void run() {
    11         if (flag) {
    12             synchronized (MyLock.objA) {
    13                 System.out.println("if objA");
    14                 synchronized (MyLock.objB) {
    15                     System.out.println("if objB");
    16                 }
    17             }
    18         } else {
    19             synchronized (MyLock.objB) {
    20                 System.out.println("else objB");
    21                 synchronized (MyLock.objA) {
    22                     System.out.println("else objA");
    23                 }
    24             }
    25         }
    26     }
    27 }

    * 分析:
    * 资源类:Student
    * 设置学生数据:SetThread(生产者)
    * 获取学生数据:GetThread(消费者)
    * 测试类:StudentDemo
    *
    * 问题1:按照思路写代码,发现数据每次都是:null---0
    * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
    * 如何实现呢?
    * 在外界把这个数据创建出来,通过构造方法传递给其他的类。
    *
    * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
    * A:同一个数据出现多次
    * B:姓名和年龄不匹配
    * 原因:
    * A:同一个数据出现多次
    * CPU的一点点时间片的执行权,就足够你执行很多次。
    * B:姓名和年龄不匹配
    * 线程运行的随机性
    * 线程安全问题:
    * A:是否是多线程环境 是
    * B:是否有共享数据 是
    * C:是否有多条语句操作共享数据 是
    * 解决方案:
    * 加锁。
    * 注意:
    * A:不同种类的线程都要加锁。
    * B:不同种类的线程加的锁必须是同一把。
    *
    * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
    * 如何实现呢?
    * 通过Java提供的等待唤醒机制解决。
    *
    * 等待唤醒:
    * Object类中提供了三个方法:
    * wait():等待
    * notify():唤醒单个线程
    * notifyAll():唤醒所有线程
    * 为什么这些方法不定义在Thread类中呢?
    * 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
    * 所以,这些方法必须定义在Object类中。

     1 public class Student {
     2     private String name;
     3     private int age;
     4     private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
     5 
     6     public synchronized void set(String name, int age) {
     7         // 如果有数据,就等待
     8         if (this.flag) {
     9             try {
    10                 this.wait();
    11             } catch (InterruptedException e) {
    12                 e.printStackTrace();
    13             }
    14         }
    15 
    16         // 设置数据
    17         this.name = name;
    18         this.age = age;
    19 
    20         // 修改标记
    21         this.flag = true;
    22         this.notify();
    23     }
    24 
    25     public synchronized void get() {
    26         // 如果没有数据,就等待
    27         if (!this.flag) {
    28             try {
    29                 this.wait();
    30             } catch (InterruptedException e) {
    31                 e.printStackTrace();
    32             }
    33         }
    34 
    35         // 获取数据
    36         System.out.println(this.name + "---" + this.age);
    37 
    38         // 修改标记
    39         this.flag = false;
    40         this.notify();
    41     }
    42 }
     1 public class GetThread implements Runnable {
     2     private Student s;
     3 
     4     public GetThread(Student s) {
     5         this.s = s;
     6     }
     7 
     8     @Override
     9     public void run() {
    10         while (true) {
    11             s.get();
    12         }
    13     }
    14 }
     1 public class SetThread implements Runnable {
     2 
     3     private Student s;
     4     private int x = 0;
     5 
     6     public SetThread(Student s) {
     7         this.s = s;
     8     }
     9 
    10     @Override
    11     public void run() {
    12         while (true) {
    13             if (x % 2 == 0) {
    14                 s.set("林青霞", 27);
    15             } else {
    16                 s.set("刘意", 30);
    17             }
    18             x++;
    19         }
    20     }
    21 }
     1 public class StudentDemo {
     2     public static void main(String[] args) {
     3         //创建资源
     4         Student s = new Student();
     5         
     6         //设置和获取的类
     7         SetThread st = new SetThread(s);
     8         GetThread gt = new GetThread(s);
     9 
    10         //线程类
    11         Thread t1 = new Thread(st);
    12         Thread t2 = new Thread(gt);
    13 
    14         //启动线程
    15         t1.start();
    16         t2.start();
    17     }
    18 }

    线程的状态转换图及常见执行情况:

    * 线程组: 把多个线程组合到一起。
    * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

     1         MyRunnable my = new MyRunnable();
     2         Thread t1 = new Thread(my, "林青霞");
     3         Thread t2 = new Thread(my, "刘意");
     4         // 我不知道他们属于那个线程组,我想知道,怎么办
     5         // 线程类里面的方法:public final ThreadGroup getThreadGroup()
     6         ThreadGroup tg1 = t1.getThreadGroup();
     7         ThreadGroup tg2 = t2.getThreadGroup();
     8         // 线程组里面的方法:public final String getName()
     9         String name1 = tg1.getName();
    10         String name2 = tg2.getName();
    11         System.out.println(name1);
    12         System.out.println(name2);
    13         // 通过结果我们知道了:线程默认情况下属于main线程组
    14         // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
    15         System.out.println(Thread.currentThread().getThreadGroup().getName());
     1         // ThreadGroup(String name)
     2         ThreadGroup tg = new ThreadGroup("这是一个新的组");
     3 
     4         MyRunnable my = new MyRunnable();
     5         // Thread(ThreadGroup group, Runnable target, String name)
     6         Thread t1 = new Thread(tg, my, "林青霞");
     7         Thread t2 = new Thread(tg, my, "刘意");
     8         
     9         System.out.println(t1.getThreadGroup().getName());
    10         System.out.println(t2.getThreadGroup().getName());
    11         
    12         //通过组名称设置后台线程,表示该组的线程都是后台线程
    13         tg.setDaemon(true);

    /*
    * 线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
    *
    * 如何实现线程的代码呢?
    * A:创建一个线程池对象,控制要创建几个线程对象。
    * public static ExecutorService newFixedThreadPool(int nThreads)
    * B:这种线程池的线程可以执行:
    * 可以执行Runnable对象或者Callable对象代表的线程
    * 做一个类实现Runnable接口。
    * C:调用如下方法即可
    * Future<?> submit(Runnable task)
    * <T> Future<T> submit(Callable<T> task)
    * D:我就要结束,可以吗?
    * 可以。

     1     public static void main(String[] args) {
     2         // 创建一个线程池对象,控制要创建几个线程对象。
     3         // public static ExecutorService newFixedThreadPool(int nThreads)
     4         ExecutorService pool = Executors.newFixedThreadPool(2);
     5 
     6         // 可以执行Runnable对象或者Callable对象代表的线程
     7         pool.submit(new MyRunnable());
     8         pool.submit(new MyRunnable());
     9 
    10         //结束线程池
    11         pool.shutdown();
    12     }

    //Callable:是带泛型的接口。
    //这里指定的泛型其实是call()方法的返回值类型。

     1 public class MyCallable implements Callable {
     2 
     3     @Override
     4     public Object call() throws Exception {
     5         for (int x = 0; x < 100; x++) {
     6             System.out.println(Thread.currentThread().getName() + ":" + x);
     7         }
     8         return null;
     9     }
    10 
    11 }

    * 多线程实现的方式3:
    * A:创建一个线程池对象,控制要创建几个线程对象。
    * public static ExecutorService newFixedThreadPool(int nThreads)
    * B:这种线程池的线程可以执行:
    * 可以执行Runnable对象或者Callable对象代表的线程
    * 做一个类实现Runnable接口。
    * C:调用如下方法即可
    * Future<?> submit(Runnable task)
    * <T> Future<T> submit(Callable<T> task)
    * D:我就要结束,可以吗?

    * 可以。

     1 /*
     2  * 线程求和案例
     3  */
     4 public class MyCallable implements Callable<Integer> {
     5 
     6     private int number;
     7 
     8     public MyCallable(int number) {
     9         this.number = number;
    10     }
    11 
    12     @Override
    13     public Integer call() throws Exception {
    14         int sum = 0;
    15         for (int x = 1; x <= number; x++) {
    16             sum += x;
    17         }
    18         return sum;
    19     }
    20 
    21 }
     1 public class CallableDemo {
     2     public static void main(String[] args) throws InterruptedException, ExecutionException {
     3         // 创建线程池对象
     4         ExecutorService pool = Executors.newFixedThreadPool(2);
     5 
     6         // 可以执行Runnable对象或者Callable对象代表的线程
     7         Future<Integer> f1 = pool.submit(new MyCallable(100));
     8         Future<Integer> f2 = pool.submit(new MyCallable(200));
     9 
    10         // V get()
    11         Integer i1 = f1.get();
    12         Integer i2 = f2.get();
    13 
    14         System.out.println(i1);
    15         System.out.println(i2);
    16 
    17         // 结束
    18         pool.shutdown();
    19     }
    20 }

     * 匿名内部类的格式:

     1         // 继承Thread类来实现多线程
     2         new Thread() {
     3             public void run() {
     4                 for (int x = 0; x < 100; x++) {
     5                     System.out.println(Thread.currentThread().getName() + ":"
     6                             + x);
     7                 }
     8             }
     9         }.start();
    10 
    11         // 实现Runnable接口来实现多线程
    12         new Thread(new Runnable() {
    13             @Override
    14             public void run() {
    15                 for (int x = 0; x < 100; x++) {
    16                     System.out.println(Thread.currentThread().getName() + ":"
    17                             + x);
    18                 }
    19             }
    20         }) {
    21         }.start();

    * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
    * 依赖Timer和TimerTask这两个类:
    * Timer:定时
    * public Timer()
    * public void schedule(TimerTask task,long delay)
    * public void schedule(TimerTask task,long delay,long period)
    * public void cancel()
    * TimerTask:任务

     1 public class TimerDemo {
     2     public static void main(String[] args) {
     3         // 创建定时器对象
     4         Timer t = new Timer();
     5         // 3秒后执行爆炸任务
     6         // t.schedule(new MyTask(), 3000);
     7         //结束任务
     8         t.schedule(new MyTask(t), 3000);
     9     }
    10 }
    11 
    12 // 做一个任务
    13 class MyTask extends TimerTask {
    14 
    15     private Timer t;
    16     
    17     public MyTask(){}
    18     
    19     public MyTask(Timer t){
    20         this.t = t;
    21     }
    22     
    23     @Override
    24     public void run() {
    25         System.out.println("beng,爆炸了");
    26         t.cancel();
    27     }
    28 
    29 }

    需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)

     1 class DeleteFolder extends TimerTask {
     2 
     3     @Override
     4     public void run() {
     5         File srcFolder = new File("demo");
     6         deleteFolder(srcFolder);
     7     }
     8 
     9     // 递归删除目录
    10     public void deleteFolder(File srcFolder) {
    11         File[] fileArray = srcFolder.listFiles();
    12         if (fileArray != null) {
    13             for (File file : fileArray) {
    14                 if (file.isDirectory()) {
    15                     deleteFolder(file);
    16                 } else {
    17                     System.out.println(file.getName() + ":" + file.delete());
    18                 }
    19             }
    20             System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
    21         }
    22     }
    23 }
    24 
    25 public class TimerTest {
    26     public static void main(String[] args) throws ParseException {
    27         Timer t = new Timer();
    28 
    29         String s = "2014-11-27 15:45:00";
    30         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    31         Date d = sdf.parse(s);
    32 
    33         t.schedule(new DeleteFolder(), d);
    34     }
    35 }

    1:多线程有几种实现方案,分别是哪几种?
    两种。

    继承Thread类
    实现Runnable接口

    扩展一种:实现Callable接口。这个得和线程池结合。

    2:同步有几种方式,分别是什么?
    两种。

    同步代码块
    同步方法

    3:启动一个线程是run()还是start()?它们的区别?
    start();

    run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
    start():启动线程,并由JVM自动调用run()方法

    4:sleep()和wait()方法的区别
    sleep():必须指时间;不释放锁。
    wait():可以不指定时间,也可以指定时间;释放锁。

    5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
    因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
    而Object代码任意的对象,所以,定义在这里面。

    6:线程的生命周期图
    新建 -- 就绪 -- 运行 -- 死亡
    新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
    建议:画图解释。

  • 相关阅读:
    091115 T UI生成的类
    090717 T OOD时的接口
    090713 T 数组不OO
    090723 T Code Generate 的思考
    091101 T IModel
    091018 CH 培训方法论总结
    090615 T 数据库范式
    写程序,逻辑优先!
    091117 T else if 的写法
    091015 CH 培训所想到的
  • 原文地址:https://www.cnblogs.com/samuraihuang/p/10041319.html
Copyright © 2020-2023  润新知