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

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

时间: 2024-10-11 09:15:09

Java笔记(24):多线程(02)的相关文章

java笔记--关于多线程如何查看JVM中运行的线程

查看JVM中的线程 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3890280.html "谢谢-- ThreadGroup(线程组)1.一个线程的集合,也可包含其他线程组2.线程组构成一棵树,除了初始化线程组外,每一个线程组都有一个父线程组3.允许线程访问有关自己的线程组的信息,但不能访问其父线程组或其他线程组的信息 常用方法:activeCount() 返回线程组中活动线程的估计数activeGroupCount() 返回线

java笔记--关于多线程状态的理解和应用

关于多线程的状态 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3890266.html  "谢谢-- 线程共有6种状态:1.新建线程---使用new来新建一个线程2.运行线程---调用start()方法,线程处于运行或可运行状态3.线程阻塞---线程需要获得内置锁,当该锁被其他线程使用时,此线程处于阻塞状态4.线程等待---当线程等待其他线程通知调度表可以运行时,此时线程处于等待状态5.线程计时等待---当线程调用含有时间参数的

Java笔记五.多线程

Java中的多线程(一) 一.理解线程 1.进程.线程.多线程 1.进程:在多任务系统中,每个独立执行的程序(或说正在进行的程序)称为进程. 2.线程:一个进程中又可以包含一个或多个线程,一个线程就是一个程序内部的一条执行线索(一部分代码). 3.多线程:如果要一程序中实现多段代码同时交替运行,就需产生多个线程,并指定每个线程上所要运行的程序代码,即为多线程. 注:在单线程中,程序代码的执行是按调用顺序依次往下执行的,不能实现两端程序代码同时交替运行的效果.当我们的程序启动运行时,会自动产生一个

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(

JAVA笔记:多线程的理解及应用(一)

进程与线程 进程是程序的一次动态执行过程,它经历了从代码加载.执行.执行结束的一个完整过程,这个过程也是整个进程的生命周期. 多线程是实现并发机制的一种有效手段.进程和线程一样,都是实现并发机制的基本单位. 传统的单核CPU在同一个时间段可以有多个程序在执行,但是只能有一个程序在某一时间点运行,所有的程序都要抢占CPU资源. 多核CPU下程序会并发执行. Java中多线程的实现 Java中要实现多线程可以通过以下两种方式: 1.继承Thread类 2.实现Runnable接口 1.继承Threa

Java笔记之多线程

/* 多线程 进程:进程就是正在进行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元 线程:线程是进程中的内容或者说是进程中的一个独立的控制单元,线程控制者进程的执行,每一个进程中至少都会有一个线程 Java虚拟机启动的时候会有一个进程java.exe该进程中至少有一个线程在负责java程序的执行,而且这个线程运行的代码 存在于main方法中 多线程存在的意义:提高了程序的运行效率 */ class ThreadMainDemo1 extends Thread 

Java笔记:多线程

一.意义 使用多线程的目的是为了提高CPU资源的利用效率.在单线程应用中程序必须等待当前任务的完成才能继续执行下一项任务,CPU在等待的时间内就闲置了,多线程的使用可减少闲置时间. 二.主线程 当Java程序启动时,会立即开始运行主线程.其他所有的线程都是从主线程产生的,主线程必须是最后才结束执行的线程,因为它需要执行各种关闭动作.可以通过currentThread静态方法获取主线程的引用. class Solution { public static void main(String[] ar

JAVA笔记:多线程的理解及应用(二)

Java中的主方法其实也是一个线程,就叫做主线程. 问:既然主方法是以线程的形式出现的,那么Java中至少有多少个线程呢? 答案:至少有两个线程.每次启动Java的时候其实都会启动JVM,则其中的垃圾回收机制也算是一个线程,则一共有两个线程,主线程和GC. 判断线程是否启动可以使用.isAlive方法,返回的是布尔值. 线程的强制运行 在线程的操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等该线程运行完毕才能执行. 线程的休眠 程序中可以实现线程短暂

java笔记--使用线程池优化多线程编程

使用线程池优化多线程编程 认识线程池 在Java中,所有的对象都是需要通过new操作符来创建的,如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下.这种时候就需要用到了池的技术,比如数据库连接池,线程池等. 在java1.5之后,java自带了线程池,在util包下新增了concurrent包,这个包主要作用就是介绍java线程和线程池如何使用的. 在包java.util.concurrent下的 Executors类中定义了Executor.ExecutorService.Sche