Java笔记(24):多线程(02)

1、JDK5之后的Lock锁的概述和使用

 1 package cn.itcast_01;
 2 
 3 import java.util.concurrent.locks.Lock;
 4 import java.util.concurrent.locks.ReentrantLock;
 5 
 6 public class SellTicket implements Runnable {
 7 
 8     // 定义票
 9     private int tickets = 100;
10 
11     // 定义锁对象
12     private Lock lock = new ReentrantLock();
13 
14     @Override
15     public void run() {
16         while (true) {
17             try {
18                 // 加锁
19                 lock.lock();
20                 if (tickets > 0) {
21                     try {
22                         Thread.sleep(100);
23                     } catch (InterruptedException e) {
24                         e.printStackTrace();
25                     }
26                     System.out.println(Thread.currentThread().getName()
27                             + "正在出售第" + (tickets--) + "张票");
28                 }
29             } finally {
30                 // 释放锁
31                 lock.unlock();
32             }
33         }
34     }
35 
36 }
 1 package cn.itcast_01;
 2 /*
 3  * 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
 4  * 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
 5  * 
 6  * Lock:
 7  *         void lock(): 获取锁。
 8  *         void unlock():释放锁。  
 9  * ReentrantLock是Lock的实现类.
10  */
11 public class SellTicketDemo {
12     public static void main(String[] args) {
13         // 创建资源对象
14         SellTicket st = new SellTicket();
15 
16         // 创建三个窗口
17         Thread t1 = new Thread(st, "窗口1");
18         Thread t2 = new Thread(st, "窗口2");
19         Thread t3 = new Thread(st, "窗口3");
20 
21         // 启动线程
22         t1.start();
23         t2.start();
24         t3.start();
25     }
26 }

2、死锁问题概述和使用

 1 package cn.itcast_02;
 2 
 3 public class DieLock extends Thread {
 4 
 5     private boolean flag;
 6 
 7     public DieLock(boolean flag) {
 8         this.flag = flag;
 9     }
10 
11     @Override
12     public void run() {
13         if (flag) {
14             synchronized (MyLock.objA) {
15                 System.out.println("if objA");
16                 synchronized (MyLock.objB) {
17                     System.out.println("if objB");
18                 }
19             }
20         } else {
21             synchronized (MyLock.objB) {
22                 System.out.println("else objB");
23                 synchronized (MyLock.objA) {
24                     System.out.println("else objA");
25                 }
26             }
27         }
28     }
29 }
 1 package cn.itcast_02;
 2 
 3 /*
 4  * 同步的弊端:
 5  *         A:效率低
 6  *         B:容易产生死锁
 7  * 
 8  * 死锁:
 9  *         两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
10  * 
11  * 举例:
12  *         中国人,美国人吃饭案例。
13  *         正常情况:
14  *             中国人:筷子两支
15  *             美国人:刀和叉
16  *         现在:
17  *             中国人:筷子1支,刀一把
18  *             美国人:筷子1支,叉一把
19  */
20 public class DieLockDemo {
21     public static void main(String[] args) {
22         DieLock dl1 = new DieLock(true);
23         DieLock dl2 = new DieLock(false);
24 
25         dl1.start();
26         dl2.start();
27     }
28 }

3、生产者消费者问题代码1

1 package cn.itcast_03;
2 
3 public class Student {
4     String name;
5     int age;
6 }
 1 package cn.itcast_03;
 2 
 3 public class SetThread implements Runnable {
 4 
 5     private Student s;
 6 
 7     public SetThread(Student s) {
 8         this.s = s;
 9     }
10 
11     @Override
12     public void run() {
13         // Student s = new Student();
14         s.name = "林青霞";
15         s.age = 27;
16     }
17 
18 }
 1 package cn.itcast_03;
 2 
 3 public class GetThread implements Runnable {
 4     private Student s;
 5 
 6     public GetThread(Student s) {
 7         this.s = s;
 8     }
 9 
10     @Override
11     public void run() {
12         // Student s = new Student();
13         System.out.println(s.name + "---" + s.age);
14     }
15 
16 }
 1 package cn.itcast_03;
 2 
 3 /*
 4  * 分析:
 5  *         资源类:Student    
 6  *         设置学生数据:SetThread(生产者)
 7  *         获取学生数据:GetThread(消费者)
 8  *         测试类:StudentDemo
 9  * 
10  * 问题1:按照思路写代码,发现数据每次都是:null---0
11  * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
12  * 如何实现呢?
13  *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
14  * 
15  */
16 public class StudentDemo {
17     public static void main(String[] args) {
18         //创建资源
19         Student s = new Student();
20         
21         //设置和获取的类
22         SetThread st = new SetThread(s);
23         GetThread gt = new GetThread(s);
24 
25         //线程类
26         Thread t1 = new Thread(st);
27         Thread t2 = new Thread(gt);
28 
29         //启动线程
30         t1.start();
31         t2.start();
32     }
33 }

4、生产者消费者题代码2并解决线程安全问题

1 package cn.itcast_04;
2 
3 public class Student {
4     String name;
5     int age;
6 }
Student
 1 package cn.itcast_04;
 2 
 3 public class SetThread implements Runnable {
 4 
 5     private Student s;
 6     private int x = 0;
 7 
 8     public SetThread(Student s) {
 9         this.s = s;
10     }
11 
12     @Override
13     public void run() {
14         while (true) {
15             synchronized (s) {
16                 if (x % 2 == 0) {
17                     s.name = "林青霞";//刚走到这里,就被别人抢到了执行权
18                     s.age = 27;
19                 } else {
20                     s.name = "刘意"; //刚走到这里,就被别人抢到了执行权
21                     s.age = 30;
22                 }
23                 x++;
24             }
25         }
26     }
27 }
 1 package cn.itcast_04;
 2 
 3 public class GetThread implements Runnable {
 4     private Student s;
 5 
 6     public GetThread(Student s) {
 7         this.s = s;
 8     }
 9 
10     @Override
11     public void run() {
12         while (true) {
13             synchronized (s) {
14                 System.out.println(s.name + "---" + s.age);
15             }
16         }
17     }
18 }
 1 package cn.itcast_04;
 2 
 3 /*
 4  * 分析:
 5  *         资源类:Student    
 6  *         设置学生数据:SetThread(生产者)
 7  *         获取学生数据:GetThread(消费者)
 8  *         测试类:StudentDemo
 9  * 
10  * 问题1:按照思路写代码,发现数据每次都是:null---0
11  * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
12  * 如何实现呢?
13  *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
14  * 
15  * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
16  *         A:同一个数据出现多次
17  *         B:姓名和年龄不匹配
18  * 原因:
19  *         A:同一个数据出现多次
20  *             CPU的一点点时间片的执行权,就足够你执行很多次。
21  *         B:姓名和年龄不匹配
22  *             线程运行的随机性
23  * 线程安全问题:
24  *         A:是否是多线程环境        是
25  *         B:是否有共享数据        是
26  *         C:是否有多条语句操作共享数据    是
27  * 解决方案:
28  *         加锁。
29  *         注意:
30  *             A:不同种类的线程都要加锁。
31  *             B:不同种类的线程加的锁必须是同一把。
32  */
33 public class StudentDemo {
34     public static void main(String[] args) {
35         //创建资源
36         Student s = new Student();
37         
38         //设置和获取的类
39         SetThread st = new SetThread(s);
40         GetThread gt = new GetThread(s);
41 
42         //线程类
43         Thread t1 = new Thread(st);
44         Thread t2 = new Thread(gt);
45 
46         //启动线程
47         t1.start();
48         t2.start();
49     }
50 }

5、生产者消费者之等待唤醒机制代码实现

1 package cn.itcast_05;
2 
3 public class Student {
4     String name;
5     int age;
6     boolean flag; // 默认情况是没有数据,如果是true,说明有数据
7 }
 1 package cn.itcast_05;
 2 
 3 public class SetThread implements Runnable {
 4 
 5     private Student s;
 6     private int x = 0;
 7 
 8     public SetThread(Student s) {
 9         this.s = s;
10     }
11 
12     @Override
13     public void run() {
14         while (true) {
15             synchronized (s) {
16                 //判断有没有
17                 if(s.flag){
18                     try {
19                         s.wait(); //t1等着,释放锁
20                     } catch (InterruptedException e) {
21                         e.printStackTrace();
22                     }
23                 }
24                 
25                 if (x % 2 == 0) {
26                     s.name = "林青霞";
27                     s.age = 27;
28                 } else {
29                     s.name = "刘意";
30                     s.age = 30;
31                 }
32                 x++; //x=1
33                 
34                 //修改标记
35                 s.flag = true;
36                 //唤醒线程
37                 s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
38             }
39             //t1有,或者t2有
40         }
41     }
42 }
package cn.itcast_05;

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(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                
                System.out.println(s.name + "---" + s.age);
                //林青霞---27
                //刘意---30
                
                //修改标记
                s.flag = false;
                //唤醒线程
                s.notify(); //唤醒t1
            }
        }
    }
}
 1 package cn.itcast_05;
 2 
 3 /*
 4  * 分析:
 5  *         资源类:Student    
 6  *         设置学生数据:SetThread(生产者)
 7  *         获取学生数据:GetThread(消费者)
 8  *         测试类:StudentDemo
 9  * 
10  * 问题1:按照思路写代码,发现数据每次都是:null---0
11  * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
12  * 如何实现呢?
13  *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
14  * 
15  * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
16  *         A:同一个数据出现多次
17  *         B:姓名和年龄不匹配
18  * 原因:
19  *         A:同一个数据出现多次
20  *             CPU的一点点时间片的执行权,就足够你执行很多次。
21  *         B:姓名和年龄不匹配
22  *             线程运行的随机性
23  * 线程安全问题:
24  *         A:是否是多线程环境        是
25  *         B:是否有共享数据        是
26  *         C:是否有多条语句操作共享数据    是
27  * 解决方案:
28  *         加锁。
29  *         注意:
30  *             A:不同种类的线程都要加锁。
31  *             B:不同种类的线程加的锁必须是同一把。
32  * 
33  * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
34  * 如何实现呢?
35  *         通过Java提供的等待唤醒机制解决。
36  * 
37  * 等待唤醒:
38  *         Object类中提供了三个方法:
39  *             wait():等待
40  *             notify():唤醒单个线程
41  *             notifyAll():唤醒所有线程
42  *         为什么这些方法不定义在Thread类中呢?
43  *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
44  *             所以,这些方法必须定义在Object类中。
45  */
46 public class StudentDemo {
47     public static void main(String[] args) {
48         //创建资源
49         Student s = new Student();
50         
51         //设置和获取的类
52         SetThread st = new SetThread(s);
53         GetThread gt = new GetThread(s);
54 
55         //线程类
56         Thread t1 = new Thread(st);
57         Thread t2 = new Thread(gt);
58 
59         //启动线程
60         t1.start();
61         t2.start();
62     }
63 }

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

 6、线程组的概述和使用

 1 package cn.itcast_06;
 2 
 3 public class MyRunnable implements Runnable {
 4 
 5     @Override
 6     public void run() {
 7         for (int x = 0; x < 100; x++) {
 8             System.out.println(Thread.currentThread().getName() + ":" + x);
 9         }
10     }
11 
12 }
 1 package cn.itcast_06;
 2 
 3 /*
 4  * 线程组: 把多个线程组合到一起。
 5  * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
 6  */
 7 public class ThreadGroupDemo {
 8     public static void main(String[] args) {
 9         // method1();
10 
11         // 我们如何修改线程所在的组呢?
12         // 创建一个线程组
13         // 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
14         method2();
15 
16         // t1.start();
17         // t2.start();
18     }
19 
20     private static void method2() {
21         // ThreadGroup(String name)
22         ThreadGroup tg = new ThreadGroup("这是一个新的组");
23 
24         MyRunnable my = new MyRunnable();
25         // Thread(ThreadGroup group, Runnable target, String name)
26         Thread t1 = new Thread(tg, my, "林青霞");
27         Thread t2 = new Thread(tg, my, "刘意");
28         
29         System.out.println(t1.getThreadGroup().getName());
30         System.out.println(t2.getThreadGroup().getName());
31         
32         //通过组名称设置后台线程,表示该组的线程都是后台线程
33         tg.setDaemon(true);
34     }
35 
36     private static void method1() {
37         MyRunnable my = new MyRunnable();
38         Thread t1 = new Thread(my, "林青霞");
39         Thread t2 = new Thread(my, "刘意");
40         // 我不知道他们属于那个线程组,我想知道,怎么办
41         // 线程类里面的方法:public final ThreadGroup getThreadGroup()
42         ThreadGroup tg1 = t1.getThreadGroup();
43         ThreadGroup tg2 = t2.getThreadGroup();
44         // 线程组里面的方法:public final String getName()
45         String name1 = tg1.getName();
46         String name2 = tg2.getName();
47         System.out.println(name1);
48         System.out.println(name2);
49         // 通过结果我们知道了:线程默认情况下属于main线程组
50         // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
51         System.out.println(Thread.currentThread().getThreadGroup().getName());
52     }
53 }

7、生产者消费者之等待唤醒机制代码优化

 1 package cn.itcast_07;
 2 
 3 public class Student {
 4     private String name;
 5     private int age;
 6     private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
 7 
 8     public synchronized void set(String name, int age) {
 9         // 如果有数据,就等待
10         if (this.flag) {
11             try {
12                 this.wait();
13             } catch (InterruptedException e) {
14                 e.printStackTrace();
15             }
16         }
17 
18         // 设置数据
19         this.name = name;
20         this.age = age;
21 
22         // 修改标记
23         this.flag = true;
24         this.notify();
25     }
26 
27     public synchronized void get() {
28         // 如果没有数据,就等待
29         if (!this.flag) {
30             try {
31                 this.wait();
32             } catch (InterruptedException e) {
33                 e.printStackTrace();
34             }
35         }
36 
37         // 获取数据
38         System.out.println(this.name + "---" + this.age);
39 
40         // 修改标记
41         this.flag = false;
42         this.notify();
43     }
44 }
 1 package cn.itcast_07;
 2 
 3 public class SetThread implements Runnable {
 4 
 5     private Student s;
 6     private int x = 0;
 7 
 8     public SetThread(Student s) {
 9         this.s = s;
10     }
11 
12     @Override
13     public void run() {
14         while (true) {
15             if (x % 2 == 0) {
16                 s.set("林青霞", 27);
17             } else {
18                 s.set("刘意", 30);
19             }
20             x++;
21         }
22     }
23 }
 1 package cn.itcast_07;
 2 
 3 public class GetThread implements Runnable {
 4     private Student s;
 5 
 6     public GetThread(Student s) {
 7         this.s = s;
 8     }
 9 
10     @Override
11     public void run() {
12         while (true) {
13             s.get();
14         }
15     }
16 }
 1 package cn.itcast_07;
 2 
 3 /*
 4  * 分析:
 5  *         资源类:Student    
 6  *         设置学生数据:SetThread(生产者)
 7  *         获取学生数据:GetThread(消费者)
 8  *         测试类:StudentDemo
 9  * 
10  * 问题1:按照思路写代码,发现数据每次都是:null---0
11  * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
12  * 如何实现呢?
13  *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
14  * 
15  * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
16  *         A:同一个数据出现多次
17  *         B:姓名和年龄不匹配
18  * 原因:
19  *         A:同一个数据出现多次
20  *             CPU的一点点时间片的执行权,就足够你执行很多次。
21  *         B:姓名和年龄不匹配
22  *             线程运行的随机性
23  * 线程安全问题:
24  *         A:是否是多线程环境        是
25  *         B:是否有共享数据        是
26  *         C:是否有多条语句操作共享数据    是
27  * 解决方案:
28  *         加锁。
29  *         注意:
30  *             A:不同种类的线程都要加锁。
31  *             B:不同种类的线程加的锁必须是同一把。
32  * 
33  * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
34  * 如何实现呢?
35  *         通过Java提供的等待唤醒机制解决。
36  * 
37  * 等待唤醒:
38  *         Object类中提供了三个方法:
39  *             wait():等待
40  *             notify():唤醒单个线程
41  *             notifyAll():唤醒所有线程
42  *         为什么这些方法不定义在Thread类中呢?
43  *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
44  *             所以,这些方法必须定义在Object类中。
45  * 
46  * 最终版代码中:
47  *         把Student的成员变量给私有的了。
48  *         把设置和获取的操作给封装成了功能,并加了同步。
49  *         设置或者获取的线程里面只需要调用方法即可。
50  */
51 public class StudentDemo {
52     public static void main(String[] args) {
53         //创建资源
54         Student s = new Student();
55         
56         //设置和获取的类
57         SetThread st = new SetThread(s);
58         GetThread gt = new GetThread(s);
59 
60         //线程类
61         Thread t1 = new Thread(st);
62         Thread t2 = new Thread(gt);
63 
64         //启动线程
65         t1.start();
66         t2.start();
67     }
68 }

8、线程池的概述和使用

 1 package cn.itcast_08;
 2 
 3 public class MyRunnable implements Runnable {
 4 
 5     @Override
 6     public void run() {
 7         for (int x = 0; x < 100; x++) {
 8             System.out.println(Thread.currentThread().getName() + ":" + x);
 9         }
10     }
11 
12 }
 1 package cn.itcast_08;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 /*
 7  * 线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
 8  * 
 9  * 如何实现线程的代码呢?
10  *         A:创建一个线程池对象,控制要创建几个线程对象。
11  *             public static ExecutorService newFixedThreadPool(int nThreads)
12  *         B:这种线程池的线程可以执行:
13  *             可以执行Runnable对象或者Callable对象代表的线程
14  *             做一个类实现Runnable接口。
15  *         C:调用如下方法即可
16  *             Future<?> submit(Runnable task)
17  *            <T> Future<T> submit(Callable<T> task)
18  *        D:我就要结束,可以吗?
19  *            可以。
20  */
21 public class ExecutorsDemo {
22     public static void main(String[] args) {
23         // 创建一个线程池对象,控制要创建几个线程对象。
24         // public static ExecutorService newFixedThreadPool(int nThreads)
25         ExecutorService pool = Executors.newFixedThreadPool(2);
26 
27         // 可以执行Runnable对象或者Callable对象代表的线程
28         pool.submit(new MyRunnable());
29         pool.submit(new MyRunnable());
30 
31         //结束线程池
32         pool.shutdown();
33     }
34 }

9、多线程方式3的思路及代码实现

 1 package cn.itcast_09;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 //Callable:是带泛型的接口。
 6 //这里指定的泛型其实是call()方法的返回值类型。
 7 public class MyCallable implements Callable {
 8 
 9     @Override
10     public Object call() throws Exception {
11         for (int x = 0; x < 100; x++) {
12             System.out.println(Thread.currentThread().getName() + ":" + x);
13         }
14         return null;
15     }
16 
17 }
 1 package cn.itcast_09;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 /*
 7  * 多线程实现的方式3:
 8  *      A:创建一个线程池对象,控制要创建几个线程对象。
 9  *             public static ExecutorService newFixedThreadPool(int nThreads)
10  *         B:这种线程池的线程可以执行:
11  *             可以执行Runnable对象或者Callable对象代表的线程
12  *             做一个类实现Runnable接口。
13  *         C:调用如下方法即可
14  *             Future<?> submit(Runnable task)
15  *            <T> Future<T> submit(Callable<T> task)
16  *        D:我就要结束,可以吗?
17  *            可以。
18  */
19 public class CallableDemo {
20     public static void main(String[] args) {
21         //创建线程池对象
22         ExecutorService pool = Executors.newFixedThreadPool(2);
23         
24         //可以执行Runnable对象或者Callable对象代表的线程
25         pool.submit(new MyCallable());
26         pool.submit(new MyCallable());
27         
28         //结束
29         pool.shutdown();
30     }
31 }

练习:多线程方式3的求和案例

 1 package cn.itcast_10;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 /*
 6  * 线程求和案例
 7  */
 8 public class MyCallable implements Callable<Integer> {
 9 
10     private int number;
11 
12     public MyCallable(int number) {
13         this.number = number;
14     }
15 
16     @Override
17     public Integer call() throws Exception {
18         int sum = 0;
19         for (int x = 1; x <= number; x++) {
20             sum += x;
21         }
22         return sum;
23     }
24 
25 }
 1 package cn.itcast_10;
 2 
 3 import java.util.concurrent.ExecutionException;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 import java.util.concurrent.Future;
 7 
 8 /*
 9  * 多线程实现的方式3:
10  *      A:创建一个线程池对象,控制要创建几个线程对象。
11  *             public static ExecutorService newFixedThreadPool(int nThreads)
12  *         B:这种线程池的线程可以执行:
13  *             可以执行Runnable对象或者Callable对象代表的线程
14  *             做一个类实现Runnable接口。
15  *         C:调用如下方法即可
16  *             Future<?> submit(Runnable task)
17  *            <T> Future<T> submit(Callable<T> task)
18  *        D:我就要结束,可以吗?
19  *            可以。
20  */
21 public class CallableDemo {
22     public static void main(String[] args) throws InterruptedException, ExecutionException {
23         // 创建线程池对象
24         ExecutorService pool = Executors.newFixedThreadPool(2);
25 
26         // 可以执行Runnable对象或者Callable对象代表的线程
27         Future<Integer> f1 = pool.submit(new MyCallable(100));
28         Future<Integer> f2 = pool.submit(new MyCallable(200));
29 
30         // V get()
31         Integer i1 = f1.get();
32         Integer i2 = f2.get();
33 
34         System.out.println(i1);
35         System.out.println(i2);
36 
37         // 结束
38         pool.shutdown();
39     }
40 }

10、匿名内部类的方式实现多线程程序

 1 package cn.itcast_11;
 2 
 3 /*
 4  * 匿名内部类的格式:
 5  *         new 类名或者接口名() {
 6  *             重写方法;
 7  *         };
 8  *         本质:是该类或者接口的子类对象。
 9  */
10 public class ThreadDemo {
11     public static void main(String[] args) {
12         // 继承Thread类来实现多线程
13         new Thread() {
14             public void run() {
15                 for (int x = 0; x < 100; x++) {
16                     System.out.println(Thread.currentThread().getName() + ":"
17                             + x);
18                 }
19             }
20         }.start();
21 
22         // 实现Runnable接口来实现多线程
23         new Thread(new Runnable() {
24             @Override
25             public void run() {
26                 for (int x = 0; x < 100; x++) {
27                     System.out.println(Thread.currentThread().getName() + ":"
28                             + x);
29                 }
30             }
31         }) {
32         }.start();
33 
34         // 更有难度的
35         new Thread(new Runnable() {
36             @Override
37             public void run() {
38                 for (int x = 0; x < 100; x++) {
39                     System.out.println("hello" + ":" + x);
40                 }
41             }
42         }) {
43             public void run() {
44                 for (int x = 0; x < 100; x++) {
45                     System.out.println("world" + ":" + x);
46                 }
47             }
48         }.start();
49     }
50 }

11、定时器的概述和使用

 1 package cn.itcast_12;
 2 
 3 import java.util.Timer;
 4 import java.util.TimerTask;
 5 
 6 /*
 7  * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
 8  * 依赖Timer和TimerTask这两个类:
 9  * Timer:定时
10  *         public Timer()
11  *         public void schedule(TimerTask task,long delay)
12  *         public void schedule(TimerTask task,long delay,long period)
13  *         public void cancel()
14  * TimerTask:任务
15  */
16 public class TimerDemo {
17     public static void main(String[] args) {
18         // 创建定时器对象
19         Timer t = new Timer();
20         // 3秒后执行爆炸任务
21         // t.schedule(new MyTask(), 3000);
22         //结束任务
23         t.schedule(new MyTask(t), 3000);
24     }
25 }
26 
27 // 做一个任务
28 class MyTask extends TimerTask {
29 
30     private Timer t;
31     
32     public MyTask(){}
33     
34     public MyTask(Timer t){
35         this.t = t;
36     }
37     
38     @Override
39     public void run() {
40         System.out.println("beng,爆炸了");
41         t.cancel();
42     }
43 
44 }

练习:定时任务的多次执行代码体现

 1 package cn.itcast_12;
 2 
 3 import java.util.Timer;
 4 import java.util.TimerTask;
 5 
 6 /*
 7  * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
 8  * 依赖Timer和TimerTask这两个类:
 9  * Timer:定时
10  *         public Timer()
11  *         public void schedule(TimerTask task,long delay)
12  *         public void schedule(TimerTask task,long delay,long period)
13  *         public void cancel()
14  * TimerTask:任务
15  */
16 public class TimerDemo2 {
17     public static void main(String[] args) {
18         // 创建定时器对象
19         Timer t = new Timer();
20         // 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
21         t.schedule(new MyTask2(), 3000, 2000);
22     }
23 }
24 
25 // 做一个任务
26 class MyTask2 extends TimerTask {
27     @Override
28     public void run() {
29         System.out.println("beng,爆炸了");
30     }
31 }

练习:定时删除指定的带内容目录

 1 package cn.itcast_12;
 2 
 3 import java.io.File;
 4 import java.text.ParseException;
 5 import java.text.SimpleDateFormat;
 6 import java.util.Date;
 7 import java.util.Timer;
 8 import java.util.TimerTask;
 9 
10 /*
11  * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
12  */
13 
14 class DeleteFolder extends TimerTask {
15 
16     @Override
17     public void run() {
18         File srcFolder = new File("demo");
19         deleteFolder(srcFolder);
20     }
21 
22     // 递归删除目录
23     public void deleteFolder(File srcFolder) {
24         File[] fileArray = srcFolder.listFiles();
25         if (fileArray != null) {
26             for (File file : fileArray) {
27                 if (file.isDirectory()) {
28                     deleteFolder(file);
29                 } else {
30                     System.out.println(file.getName() + ":" + file.delete());
31                 }
32             }
33             System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
34         }
35     }
36 }
37 
38 public class TimerTest {
39     public static void main(String[] args) throws ParseException {
40         Timer t = new Timer();
41 
42         String s = "2014-11-27 15:45:00";
43         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
44         Date d = sdf.parse(s);
45 
46         t.schedule(new DeleteFolder(), d);
47     }
48 }

12、多线程总结

/*
 *    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:线程的生命周期图
 *        新建 -- 就绪 -- 运行 -- 死亡
 *        新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
 */

 --干了每滴寂寞 进化成更好的我 等着你 在我世界 路过... ...

如欢如殇 授以青春鲜活肢体奔忙 如思如忘 驱以老朽深沉灵魂冥想 始自情热激荡 从未敢终于世事炎凉 无能执手相望 无法去尝试结发同床 无力至心死身僵 一息坚强 ------ 我一直没有放弃,如果你也能看到 修身 修禅
原文地址:https://www.cnblogs.com/lz2lhy/p/7011588.html