java之多线程

多线程

并发和并行

并发:指两个或多个事件在同一个时间段内发生。java

并行:指两个或多个事件在同一时刻发生(同时发生)。编程

建立线程

Thread类

 java.lang.Thread 类安全

构造方法

public Thread() :分配一个新的线程对象。多线程

public Thread(String name) :分配一个指定名字的新的线程对象。并发

public Thread(Runnable target) :分配一个带有指定目标新的线程对象。ide

public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。测试

经常使用方法

public void start() :致使此线程开始执行; Java虚拟机调用此线程的run方法。this

  多线程的开启方式只有调用start方法开启。spa

public String getName() :获取当前线程名称。线程

public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

 1 /*
 2 * 获取线程的名称:
 3 *       1,使用Thread类中的getName()方法
 4 *           String getName()  返回该线程的名称
 5 *       2,能够先获取到当前正在执行的线程。使用线程中的方法getName()获取线程的名称
 6 *           static Thread currentThread() 返回对当前正在执行的线程对象的引用
 7 * */
 8 
 9 
10 public class MyThread extends Thread {
11 
12     @Override
13     public void run(){
14         // 获取线程的名称
15 
16         // String name = getName();
17         // System.out.println(name);
18 
19 
20         // Thread t = Thread.currentThread();
21         // System.out.println(t);
22         //
23         // String name = t.getName();
24         // System.out.println(name);
25 
26 
27         // 链式编程
28         System.out.println(Thread.currentThread().getName());
29     }
30 }
31 
32 
33 -------------------------------------------------------------
34 /*
35 * 线程的名称:
36 *       主线程:main
37 *       新线程:Thread-0,Thread-1
38 * */
39 
40 public class Demo01GetThreadName {
41     public static void main(String[] args) {
42         // 建立Thread类的子类对象
43         MyThread mt = new MyThread();
44 
45         // 调用start方法,开启新线程执行run方法
46         mt.start();
47 
48         new MyThread().start();
49         new MyThread().start();
50 
51         System.out.println(Thread.currentThread().getName());
52 
53     }
54 }
代码示例

public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时中止执行)。

 1 /*
 2 * public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时中止执行)。
 3 *       毫秒数结束以后,线程继续执行
 4 */
 5 
 6 public class Demo01Sleep {
 7     public static void main(String[] args) {
 8         // 模拟秒表
 9         for(int i =0;i<60;i++){
10 
11             System.out.println(i);
12 
13             // 使用Thread类中的sleep方法让程序睡眠1秒
14             try {
15                 Thread.sleep(1000);
16             } catch (InterruptedException e) {
17                 e.printStackTrace();
18             }
19         }
20     }
21 }
View Code

第一种方式——建立Thread类的子类

java.long.Thread类:是描述线程的类,咱们想要实现多线程程序,就必须继承Thread类

实现步骤:

1,建立一个Thread类的子类

2,在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要干的事)

3,建立Thread类的子类对象

4,调用Thread类中的方法start方法,开启新的线程,执行run方法【start方法自动去子类中找run方法执行】

  void start() 使该线程开始执行;java虚拟机调用该线程的run方法

  结果是两个线程并发的运行,当前线程(main线程)和另外一个线程(建立的新线程,执行其run方法)。

  屡次启动一个线程是非法的。特别是当前线程已经结束执行后,不能再从新启动

 1 //1.建立一个Thread类的子类
 2 public class MyThread extends Thread {
 3 
 4     //2,在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要干的事)
 5     @Override
 6     public void run() {
 7         for (int i = 0; i < 20; i++) {
 8             System.out.println("run" + i);
 9         }
10     }
11 }
12 
13 
14 ---------------------------------------------------------------
15 public class Demo01Thread {
16 
17     public static void main(String[] args) {
18         // 3,建立Thread类的子类对象
19         MyThread my = new MyThread();
20 
21         //4,调用Thread类中的方法start方法,开启新的线程,执行run方法
22         my.start();
23 
24         //my.start();错误的,屡次启动一个线程非法
25 
26         for (int i = 0; i < 20; i++) {
27             System.out.println("main" + i);
28         }
29     }
30 }
多线程第一种方式代码实现

注意:java程序属于抢占式调度,那个线程优先级高,那个线程就优先执行。同一个优先级就随机选一个执行

多线程的流程图解和内存图解:

第二种方式——实现Runnable接口

java.long.Runnable:Runnable 接口应该由那些打算经过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。

java.long.Thread类的构造方法

  Thread(Runnable target)分配新的 Thread 对象。

  Thread(Runnable target, String name)分配新的 Thread 对象

实现步骤:

  1,建立一个Runnable接口的实现类

  2,在实现类中重写Runnable接口中的run方法,设置线程任务。

  3,建立一个Runnable接口的实现类对象

  4,建立一个Thread类对象,参数中传递Runnable接口的实现类对象

  5,调用Thread类中的start方法开启新的线程执行run方法

 1 // 1,建立一个Runnable接口的实现类
 2 public class RunnableImp implements Runnable {
 3 
 4     // 2,在实现类中重写Runnable接口中的run方法,设置线程任务。
 5     @Override
 6     public void run() {
 7         for (int i = 0; i < 20; i++) {
 8             System.out.println(Thread.currentThread().getName() + i);
 9         }
10     }
11 }
12 
13 
14 -----------------------------------------------------------------
15 public class Dem01Runnable {
16     public static void main(String[] args) {
17         // 3,建立一个Runnable接口的实现类对象
18         RunnableImp run = new RunnableImp();
19 
20         // 4,建立一个Thread类对象,参数中传递Runnable接口的实现类对象
21         // Thread t = new Thread(run);// 打印线程名称
22         Thread t = new Thread(new RunnableImp2());// 打印hello world
23 
24         // 5,调用Thread类中的start方法开启新的线程执行run方法
25         t.start();
26 
27         for (int i = 0; i < 20; i++) {
28             System.out.println(Thread.currentThread().getName()+i);
29         }
30     }
31 }
实现多线程方式二实现Runnable接口

两种方式的比较

实现Runnable接口建立多线程的好处:

1,避免了单继承的局限性:一个类只能继承一个类(一我的只能有一个亲爹),类继承了Thread类就不能继承其余的类。

    实现了Runnable便可,还能够继承其余的类,实现其余的接口

2,加强了程序的扩展性,下降了程序的耦合性(解耦):实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)

    1)实现类中,重写了run方法:用来设置线程任务。

    2)建立Thread类对象,调用start方法:用来开启多线程。

匿名内部类的方式实现多线程的建立

匿名内部类方法实现线程的建立

  匿名:没有名字

  内部类:写在其余类内部的类

匿名内部类的做用:简化代码

  把子类继承父类,重写父类的方法,建立子类对象集合一步完成

  把实现类实现接口,重写接口中的方法,建立实现类对象合成一步完成

匿名内部类的最终产物:子类/实现类对象,而这个类没有名字

格式:

1 new 父类/接口(){
2     重写父类/接口中的方法
3 };
 1 public class Demo01InnerClassThread {
 2 
 3     public static void main(String[] args) {
 4         // 线程的父类是Thread
 5         // 原来的步骤:new MyThread子类,调用start方法
 6 
 7         new Thread(){
 8             // 重写run方法,设置线程任务
 9             @Override
10             public void run(){
11                 for (int i = 0; i < 20; i++) {
12                     System.out.println(Thread.currentThread().getName()+"哈哈哈");
13                 }
14             }
15         }.start();
16 
17 
18 
19 
20         // 线程的接口Runnable
21         // Runnable r = new RunnableImp()
22 
23         Runnable run = new Runnable(){
24             @Override
25             public void run(){
26                 for (int i = 0; i < 20; i++) {
27                     System.out.println(Thread.currentThread().getName()+"呜呜呜");
28                 }
29             }
30         };
31 
32         new Thread(run).start();
33 
34 
35 
36         // 简化接口的方式
37         new Thread(new Runnable() {
38             @Override
39             public void run() {
40                 for (int i = 0; i < 20; i++) {
41                     System.out.println(Thread.currentThread().getName()+"嗯嗯嗯");
42 
43                 }
44             }
45         }).start();
46 
47     }
48 }
匿名内部类实现多线程代码示例

线程安全

线程安全

定义:若是有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是同样 的,并且其余的变量的值也和预期的是同样的,就是线程安全的。

在多线程中可能出现哪些不安全现象

下面使用一个卖票案例显示可能出现的问题

 1 /*
 2 实现买票案例
 3  */
 4 public class RunnableImp implements Runnable {
 5     // 定义一个多个线程共享的票源
 6     private int ticket = 100;
 7 
 8     // 设置线程任务:买票
 9     @Override
10     public void run() {
11         // 使用死循环,让买票操做重复执行
12         while (true){
13             // 判断票是否存在
14             if (ticket>0){
15                 // 提升安全问题出现的几率,让程序睡眠
16                 try {
17                     Thread.sleep(10);
18                 } catch (InterruptedException e) {
19                     e.printStackTrace();
20                 }
21 
22 
23                 // 票存在,卖票
24                 System.out.println(Thread.currentThread().getName()+"--->正在卖第"+ticket+"票");
25                 ticket--;
26             }
27         }
28     }
29 }
30 
31 
32 
33 
34 --------------------------------------------------------
35 /*
36 模拟卖票案例:
37     建立三个线程,同时开启,对共享的票出售
38  */
39 public class Demo01Ticket {
40     public static void main(String[] args) {
41         // 建立Runnable接口的实现类对象
42         RunnableImp run = new RunnableImp();
43 
44         // 一个实现类让三个线程访问
45 
46         // 建立Thread类对象,构造方法中传递Runnable接口的实现类对象
47         Thread t1 = new Thread(run);
48         Thread t2 = new Thread(run);
49         Thread t3 = new Thread(run);
50 
51         // 开启多线程
52         t1.start();
53         t2.start();
54         t3.start();
55 
56         // 输出的有不存在的票和重复的票
57     }
58 }
View Code

输出结果的部分截图

发现程序出现了两个问题:

1. 相同的票数,好比5这张票被卖了两回。

2. 不存在的票,好比0票与-1票,是不存在的

线程不安全:这种问题,几个窗口(线程)票数不一样步了,这种问题称为线程不安全

线程同步

当咱们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操做,就容易出现线程安全问题。

要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不存在票问题,Java中提供了同步机制 (synchronized)来解决

线程同步的三种实现方式:

  1. 同步代码块。

  2. 同步方法。

  3. 锁机制。

同步代码块

语法:

1  synchronized(锁对象){
2      可能会出现线程安全问题的代码(访问了共享数据的代码)
3  }

注意:

    1,经过代码块中的锁对象,可使用任意的对象作为锁对象

    2,可是必须保证多个线程使用的锁对象是同一个

    3,锁对象的做用:把同步代码块锁住,只让一个线程在同步代码块中执行

 1 public class RunnableImp implements Runnable {
 2     // 定义一个多个线程共享的票源
 3     private int ticket = 100;
 4 
 5     // 建立一个锁对象
 6     Object obj = new Object();
 7 
 8 
 9     // 设置线程任务:买票
10     @Override
11     public void run() {
12         // 使用死循环,让买票操做重复执行
13         while (true) {
14             // 建立同步代码块
15             synchronized (obj) {
16                 // 判断票是否存在
17                 if (ticket > 0) {
18                     // 提升安全问题出现的几率,让程序睡眠
19                     try {
20                         Thread.sleep(100);
21                     } catch (InterruptedException e) {
22                         e.printStackTrace();
23                     }
24 
25 
26                     // 票存在,卖票
27                     System.out.println(Thread.currentThread().getName() + "--->正在卖第" + ticket + "票");
28                     ticket--;
29                 }
30             }
31         }
32     }
33 }
34 
35 
36 
37 
38 -------------------------------------------------------------------------------
39 public class Demo01Ticket {
40     public static void main(String[] args) {
41         // 建立Runnable接口的实现类对象
42         RunnableImp run = new RunnableImp();
43 
44         // 一个实现类让三个线程访问
45 
46         // 建立Thread类对象,构造方法中传递Runnable接口的实现类对象
47         Thread t1 = new Thread(run);
48         Thread t2 = new Thread(run);
49         Thread t3 = new Thread(run);
50 
51         // 开启多线程
52         t1.start();
53         t2.start();
54         t3.start();
55     }
56 }
View Code

同步方法

格式:

1  修饰符 synchronized 返回值类型 方法名(参数列表){
2      可能出现线程安全问题的代码(访问了共享数据的代码)
3  }

使用步骤:

    1,访问了共享数据的代码抽取出来,放在一个方法中

    2,在方法上添加synchronized修饰符

 1 public class RunnableImp implements Runnable {
 2     // 定义一个多个线程共享的票源
 3     private static int ticket = 100;
 4 
 5 
 6     // 设置线程任务:买票
 7     @Override
 8     public void run() {
 9         // 使用死循环,让买票操做重复执行
10         while (true) {
11             // 判断票是否存在
12             // payTicket();
13             payTicketStatic();
14         }
15     }
16 
17     // 静态同步方法
18     /*
19     * 锁对象是谁?
20     * 不能是this
21     * this是建立对象以后产生的,静态方法优先于对象
22     * 静态方法的锁对象是本类的class属性--->class文件对象
23     *
24     * */
25 
26     public static synchronized void payTicketStatic() {
27         if (ticket > 0) {
28             // 提升安全问题出现的几率,让程序睡眠
29             try {
30                 Thread.sleep(10);
31             } catch (InterruptedException e) {
32                 e.printStackTrace();
33             }
34 
35 
36             // 票存在,卖票
37             System.out.println(Thread.currentThread().getName() + "--->正在卖第" + ticket + "票");
38             ticket--;
39         }
40     }
41 
42 
43     // 定义一个同步方法
44     /*
45      * 同步方法也会把方法内部的代码锁住
46      * 只让一个线程执行
47      * 同步方法的锁对象是谁?
48      * 就是实现类对象  new RunnableImp()
49      * 也就是this
50      *
51      * */
52     public synchronized void payTicket() {
53         if (ticket > 0) {
54             // 提升安全问题出现的几率,让程序睡眠
55             try {
56                 Thread.sleep(10);
57             } catch (InterruptedException e) {
58                 e.printStackTrace();
59             }
60 
61 
62             // 票存在,卖票
63             System.out.println(Thread.currentThread().getName() + "--->正在卖第" + ticket + "票");
64             ticket--;
65         }
66     }
67 }
68 
69 
70 
71 ------------------------------------------------------------------
72 public class Demo01Ticket {
73     public static void main(String[] args) {
74         // 建立Runnable接口的实现类对象
75         RunnableImp run = new RunnableImp();
76 
77         // 一个实现类让三个线程访问
78 
79         // 建立Thread类对象,构造方法中传递Runnable接口的实现类对象
80         Thread t1 = new Thread(run);
81         Thread t2 = new Thread(run);
82         Thread t3 = new Thread(run);
83 
84         // 开启多线程
85         t1.start();
86         t2.start();
87         t3.start();
88 
89         // 输出的有不存在的票和重复的票
90     }
91 }
View Code

锁机制(Lock锁)

java.util.concurrent.locks.lock接口:Lock 实现提供了比使用 synchronized 方法和语句可得到的更普遍的锁定操做。

Lock接口中的方法:

    void lock() 获取锁。

    void unlock() 释放锁。

Lock为接口,因此咱们使用其实现类(ReentrantLock):java.util.concurrent.locks.ReentrantLock implements Lock

使用步骤:

    1,在成员位置建立一个Lock实现类对象ReentrantLock对象

    2,在可能出现安全问题的代码前调用Lock接口中的方法lock获取锁

    3,在可能出现安全问题的代码后调用Lock接口中的方法unlock释放锁

 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3 
 4 public class RunnableImp implements Runnable {
 5     // 定义一个多个线程共享的票源
 6     private int ticket = 100;
 7 
 8     // 1,在成员位置建立一个Lock实现类对象ReentrantLock对象
 9     Lock l = new ReentrantLock();
10 
11 
12 
13     // // 设置线程任务:买票
14     // @Override
15     // public void run() {
16     //     // 使用死循环,让买票操做重复执行
17     //     while (true){
18     //
19     //         //  2,在可能出现安全问题的代码前调用Lock接口中的方法lock获取锁
20     //         l.lock();
21     //         // 判断票是否存在
22     //         if (ticket>0){
23     //              // 提升安全问题出现的几率,让程序睡眠
24     //             try {
25     //                 Thread.sleep(10);
26     //             } catch (InterruptedException e) {
27     //                 e.printStackTrace();
28     //             }
29     //
30     //
31     //             // 票存在,卖票
32     //             System.out.println(Thread.currentThread().getName()+"--->正在卖第"+ticket+"票");
33     //             ticket--;
34     //         }
35     //
36     //         // 3,在可能出现安全问题的代码后调用Lock接口中的方法unlock释放锁
37     //         l.unlock();
38     //     }
39     // }
40 
41 
42     // 更好的写法
43 
44     // 设置线程任务:买票
45     @Override
46     public void run() {
47         // 使用死循环,让买票操做重复执行
48         while (true){
49 
50             //  2,在可能出现安全问题的代码前调用Lock接口中的方法lock获取锁
51             l.lock();
52             // 判断票是否存在
53             if (ticket>0){
54                 // 提升安全问题出现的几率,让程序睡眠
55                 try {
56                     Thread.sleep(10);
57                     // 票存在,卖票
58                     System.out.println(Thread.currentThread().getName()+"--->正在卖第"+ticket+"票");
59                     ticket--;
60                 } catch (InterruptedException e) {
61                     e.printStackTrace();
62                 } finally {
63                     // 不管程序出现不出现异常,都会把锁释放
64                     // 3,在可能出现安全问题的代码后调用Lock接口中的方法unlock释放锁
65                     l.unlock();
66                 }
67             }
68         }
69     }
70 }
71 
72 
73 -----------------------------------------------------------
74 public class Demo01Ticket {
75     public static void main(String[] args) {
76         // 建立Runnable接口的实现类对象
77         RunnableImp run = new RunnableImp();
78 
79         // 一个实现类让三个线程访问
80 
81         // 建立Thread类对象,构造方法中传递Runnable接口的实现类对象
82         Thread t1 = new Thread(run);
83         Thread t2 = new Thread(run);
84         Thread t3 = new Thread(run);
85 
86         // 开启多线程
87         t1.start();
88         t2.start();
89         t3.start();
90     }
91 }
View Code

线程状态

各类状态之间的互相转换

等待唤醒机制

Object类中关于线程的方法

多线程中在使用锁对象的时候,大多数使用Object类来建立对象,由于该对象中有一些关于多线程的方法

Object类中的方法:

     void wait(long timeout) :在其余线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,致使当前线程等待。

     void wait()在其余线程调用此对象的 notify() 方法或 notifyAll() 方法前,致使当前线程等待。

     void notify() 唤醒在此对象监视器上等待的单个线程。会执行wait以后的代码

     void notifyAll() :唤醒在此对象监视器上等待的全部线程。

线程通讯

 1 /*
 2 等待唤醒案例:线程之间的通讯
 3     建立一个顾客线程(消费者):告知老板要的包子的种类和数量,调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
 4     建立一个老板线程(消费者):花了5秒作包子,包子作好以后调用notify()方法,唤醒顾客吃包子
 5 
 6 
 7 注意:
 8     顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
 9     同步使用的锁对象必须保证惟一
10     只有锁对象才能调用wait和notify方法
11  */
12 
13 
14 public class Demo01WaitAndNotify {
15     public static void main(String[] args) {
16         Object obj = new Object();
17 
18         //  建立一个老板线程(生产者)
19         new Thread() {
20             @Override
21             public void run() {
22                 // 一直作包子
23                 while (true){
24                     // 花5秒作包子
25                     try {
26                         Thread.sleep(5000);
27                     } catch (InterruptedException e) {
28                         e.printStackTrace();
29                     }
30                     // 保证等待和唤醒的线程只能有一个在执行
31                     synchronized (obj) {
32 
33                         System.out.println("老板5秒中以后作好包子,告知顾客能够吃包子了");
34                         // 调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
35                         obj.notify();
36                     }
37                 }
38             }
39         }.start();
40 
41 
42         new Thread(){
43             @Override
44             public void run() {
45                 // 一直等着买包子
46                 while (true){
47                     // 保证等待和唤醒的线程只能有一个在执行
48                     synchronized (obj) {
49                         System.out.println("告知老板要的包子种类和数量");
50                         // 调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
51                         try {
52                             obj.wait();
53                         } catch (InterruptedException e) {
54                             e.printStackTrace();
55                         }
56                         // 唤醒以后执行的代码
57                         System.out.println("包子作好了,开吃");
58                         System.out.println("---------------------");
59                     }
60                 }
61             }
62         }.start();
63     }
64 }
线程通讯——唤醒锁对象的一个线程
 1 public class Demo02WaitAndNotify {
 2     public static void main(String[] args) {
 3 
 4         Object obj = new Object();
 5 
 6 
 7         new Thread(){
 8             @Override
 9             public void run() {
10                 // 一直等着买包子
11                 while (true){
12                     // 保证等待和唤醒的线程只能有一个在执行
13                     synchronized (obj) {
14                         System.out.println("顾客1:告知老板要的包子种类和数量");
15                         // 调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
16                         try {
17                             obj.wait();
18                         } catch (InterruptedException e) {
19                             e.printStackTrace();
20                         }
21                         // 唤醒以后执行的代码
22                         System.out.println("顾客1:包子作好了,开吃");
23                         System.out.println("---------------------");
24                     }
25                 }
26             }
27         }.start();
28 
29         new Thread(){
30             @Override
31             public void run() {
32                 // 一直等着买包子
33                 while (true){
34                     // 保证等待和唤醒的线程只能有一个在执行
35                     synchronized (obj) {
36                         System.out.println("顾客2:告知老板要的包子种类和数量");
37                         // 调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
38                         try {
39                             obj.wait();
40                         } catch (InterruptedException e) {
41                             e.printStackTrace();
42                         }
43                         // 唤醒以后执行的代码
44                         System.out.println("顾客2:包子作好了,开吃");
45                         System.out.println("---------------------");
46                     }
47                 }
48             }
49         }.start();
50 
51 
52         //  建立一个老板线程(生产者)
53         new Thread() {
54             @Override
55             public void run() {
56                 // 一直作包子
57                 while (true){
58                     // 花5秒作包子
59                     try {
60                         Thread.sleep(5000);
61                     } catch (InterruptedException e) {
62                         e.printStackTrace();
63                     }
64                     // 保证等待和唤醒的线程只能有一个在执行
65                     synchronized (obj) {
66 
67                         System.out.println("老板5秒中以后作好包子,告知顾客能够吃包子了");
68                         // 调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
69                         // 若是有多个等待线程随机唤醒一个等待
70                         //obj.notify();
71 
72                         //若是多个等待的线程唤醒全部
73                         obj.notifyAll();
74                     }
75                 }
76             }
77         }.start();
78     }
79 }
线程通讯——唤醒锁对象的全部的线程

生产者消费者问题

  1 /*
  2     资源类:包子类
  3     设置包子的属性
  4   5   6         包子的状态: 有 true,没有 false
  7  */
  8 public class BaoZi {
  9     //
 10     String pi;
 11     //
 12     String xian;
 13     //包子的状态: 有 true,没有 false,设置初始值为false没有包子
 14     boolean flag = false;
 15 
 16 }
 17 
 18 
 19 ------------------------------------------------------------------
 20 /*
 21     消费者(吃货)类:是一个线程类,能够继承Thread
 22     设置线程任务(run):吃包子
 23     对包子的状态进行判断
 24     false:没有包子
 25         吃货调用wait方法进入等待状态
 26     true:有包子
 27         吃货吃包子
 28         吃货吃完包子
 29         修改包子的状态为false没有
 30         吃货唤醒包子铺线程,生产包子
 31  */
 32 public class ChiHuo extends Thread{
 33     //1.须要在成员位置建立一个包子变量
 34     private BaoZi bz;
 35 
 36     //2.使用带参数构造方法,为这个包子变量赋值
 37     public ChiHuo(BaoZi bz) {
 38         this.bz = bz;
 39     }
 40     //设置线程任务(run):吃包子
 41     @Override
 42     public void run() {
 43         //使用死循环,让吃货一直吃包子
 44         while (true){
 45             //必须同时同步技术保证两个线程只能有一个在执行
 46             synchronized (bz){
 47                 //对包子的状态进行判断
 48                 if(bz.flag==false){
 49                     //吃货调用wait方法进入等待状态
 50                     try {
 51                         bz.wait();
 52                     } catch (InterruptedException e) {
 53                         e.printStackTrace();
 54                     }
 55                 }
 56 
 57                 //被唤醒以后执行的代码,吃包子
 58                 System.out.println("吃货正在吃:"+bz.pi+bz.xian+"的包子");
 59                 //吃货吃完包子
 60                 //修改包子的状态为false没有
 61                 bz.flag = false;
 62                 //吃货唤醒包子铺线程,生产包子
 63                 bz.notify();
 64                 System.out.println("吃货已经把:"+bz.pi+bz.xian+"的包子吃完了,包子铺开始生产包子");
 65                 System.out.println("----------------------------------------------------");
 66             }
 67         }
 68     }
 69 }
 70 
 71 
 72 -------------------------------------------------------------------
 73 /*
 74     生产者(包子铺)类:是一个线程类,能够继承Thread
 75     设置线程任务(run):生产包子
 76     对包子的状态进行判断
 77     true:有包子
 78         包子铺调用wait方法进入等待状态
 79     false:没有包子
 80         包子铺生产包子
 81         增长一些趣味性:交替生产两种包子
 82             有两种状态(i%2==0)
 83         包子铺生产好了包子
 84         修改包子的状态为true有
 85         唤醒吃货线程,让吃货线程吃包子
 86 
 87     注意:
 88         包子铺线程和包子线程关系-->通讯(互斥)
 89         必须同时同步技术保证两个线程只能有一个在执行
 90         锁对象必须保证惟一,可使用包子对象做为锁对象
 91         包子铺类和吃货的类就须要把包子对象做为参数传递进来
 92             1.须要在成员位置建立一个包子变量
 93             2.使用带参数构造方法,为这个包子变量赋值
 94  */
 95 public class BaoZiPu extends Thread{
 96     //1.须要在成员位置建立一个包子变量
 97     private BaoZi bz;
 98 
 99     //2.使用带参数构造方法,为这个包子变量赋值
100     public BaoZiPu(BaoZi bz) {
101         this.bz = bz;
102     }
103 
104     //设置线程任务(run):生产包子
105     @Override
106     public void run() {
107         //定义一个变量
108         int count = 0;
109         //让包子铺一直生产包子
110         while(true){
111             //必须同时同步技术保证两个线程只能有一个在执行
112             synchronized (bz){
113                 //对包子的状态进行判断
114                 if(bz.flag==true){
115                     //包子铺调用wait方法进入等待状态
116                     try {
117                         bz.wait();
118                     } catch (InterruptedException e) {
119                         e.printStackTrace();
120                     }
121                 }
122 
123                 //被唤醒以后执行,包子铺生产包子
124                 //增长一些趣味性:交替生产两种包子
125                 if(count%2==0){
126                     //生产 薄皮三鲜馅包子
127                     bz.pi = "薄皮";
128                     bz.xian = "三鲜馅";
129                 }else{
130                     //生产 冰皮 牛肉大葱陷
131                     bz.pi = "冰皮";
132                     bz.xian = "牛肉大葱陷";
133 
134                 }
135                 count++;
136                 System.out.println("包子铺正在生产:"+bz.pi+bz.xian+"包子");
137                 //生产包子须要3秒钟
138                 try {
139                     Thread.sleep(3000);
140                 } catch (InterruptedException e) {
141                     e.printStackTrace();
142                 }
143                 //包子铺生产好了包子
144                 //修改包子的状态为true有
145                 bz.flag = true;
146                 //唤醒吃货线程,让吃货线程吃包子
147                 bz.notify();
148                 System.out.println("包子铺已经生产好了:"+bz.pi+bz.xian+"包子,吃货能够开始吃了");
149             }
150         }
151     }
152 }
153 
154 
155 --------------------------------------------------------------
156 /*
157     测试类:
158     包含main方法,程序执行的入口,启动程序
159     建立包子对象;
160     建立包子铺线程,开启,生产包子;
161     建立吃货线程,开启,吃包子;
162  */
163 public class Demo {
164     public static void main(String[] args) {
165         //建立包子对象;
166         BaoZi bz =new BaoZi();
167         //建立包子铺线程,开启,生产包子;
168         new BaoZiPu(bz).start();
169         //建立吃货线程,开启,吃包子;
170         new ChiHuo(bz).start();
171     }
172 }
View Code

 

线程池

线程池(JDK1.5以后提供):其实就是一个容纳多个线程的容器,其中的线程能够反复使用,省去了频繁建立线程对象的操做,无需反复建立线程而消耗过多资源。 

 

 

java.util.concurrent.Executors:线程池工程类,用来生产线程池

 

  Executors类中的静态方法:static ExecutorService newFixedThreadPool(int nThreads):建立一个可重用固定线程数的线程池

    参数:int nThreads:建立线程池中包含的线程数量

    返回值:ExecutorService接口:返回的是ExecutorService接口的实现类对象,可使用ExecutorService接收

java.util.ExecutorService:线程池接口。用来从线程池中获取线程,调用start方法,执行线程任务

  提交一个Runnable任务用于执行:submit(Runnable task)

  关闭/销毁 线程池的方法:void shutdown()

使用步骤:

1,使用线程池的工厂类Executors里面提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池

2,建立一个类,实现Runnable接口,重写run方法,设置线程任务

3,调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程执行run方法

4,调用ExecutorService中的方法shutdown销毁线程池(不建议执行)

 1 public class RunableImpl implements Runnable {
 2 
 3     @Override
 4     public void run(){
 5         System.out.println(Thread.currentThread().getName()+"建立了一个新的线程并执行");
 6     }
 7 }
 8 
 9 
10 ------------------------------------------------------------------
11 import java.util.concurrent.ExecutorService;
12 import java.util.concurrent.Executors;
13 
14 public class Demo01ThreadPool {
15 
16     public static void main(String[] args) {
17         ExecutorService es = Executors.newFixedThreadPool(2);
18 
19         es.submit(new RunableImpl());//pool-1-thread-2建立了一个新的线程并执行
20         es.submit(new RunableImpl());//pool-1-thread-1建立了一个新的线程并执行
21         es.submit(new RunableImpl());//pool-1-thread-1建立了一个新的线程并执行
22         es.submit(new RunableImpl());//pool-1-thread-1建立了一个新的线程并执行
23 
24         //  4,调用ExecutorService中的方法shutdown销毁线程池(不建议执行)
25         es.shutdown();
26     }
27 }
View Code

 

 

 

 

 

 

 

 

 

 

---------------------------

相关文章
相关标签/搜索