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

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

    如欢如殇 授以青春鲜活肢体奔忙 如思如忘 驱以老朽深沉灵魂冥想 始自情热激荡 从未敢终于世事炎凉 无能执手相望 无法去尝试结发同床 无力至心死身僵 一息坚强 ------ 我一直没有放弃,如果你也能看到 修身 修禅
  • 相关阅读:
    BZOJ4503 两个串
    【挖坟】HDU3205 Factorization
    webpack打包 The 'mode' option has not been set, webpack will fallback to
    echarts js报错 Cannot read property 'getAttribute' of null
    微信支付 get_brand_wcpay_request fail,Undefined variable: openid
    layui动态设置checbox选中状态
    layui 获取radio单选框选中的值
    js 获取数组最后一个元素
    js生成指定范围内的随机数
    layer重复弹出(layui弹层同时存在多个)的解决方法
  • 原文地址:https://www.cnblogs.com/lz2lhy/p/7011588.html
Copyright © 2020-2023  润新知