java--多线程(1)--黑马程序员

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

多线程(1)

主要内容:《 多线程概述与例子、实现的方式1、获取线程的名称、优先级、sleep、join、yield、setDeamon、stop_interrupt、实现的方式2、Lock锁、死锁》

1.多线程概述

1.进程:
   1).这是"操作系统"中的概念,每个独立运行的程序,就是一个"进程";
   2).一个操作系统可以维护多个"进程"的同时运行,同一分配"系统资源";
   3).一个操作系统可以维护多个"进程",这叫:支持"多进程"。
 多进程"的意义:
   A.可以充分利用CPU的资源;
  B.为客户的使用提供了很好支持;客户可以同时启动多个软件;
2.线程:
   1).一个"进程"内部的一些"代码块",可以以"独立于此进程"的方式单独运行。它可以与此进程
        同时竞争"系统资源"。这些由"进程"内部以独立的方式运行的代码,就叫做:线程;
   2).意义:
     A.可以提高程序的运行效率;
     B.可以提高CPU的使用效率;

3.多进程和多线程:
   1.多进程:相对操作系统,可以同时运行多个应用程序,这个就叫:多进程;
   2.多线程:一个主"进程",可以开出多个"线程"单独运行,这个就叫:多线程;
   3.单线程:以前我们做的都是"单线程"程序,只有一条执行路径;
   4.并行和并发:
     1.并行:是指"在某个时间段内",两个线程同时运行;
     2.并发:是指"在某个时间点上",同时发生。尤其是指,多个线程同时访问同一资源时;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         fun1();
 4         fun2();//必须要等待fun1()执行完毕
 5         for(int i = 1 ; i < 1000 ; i++){//主进程的for循环必须要等待fun2()执行完毕;
 6             System.out.println("i = " + i);
 7         }
 8     }
 9
10     private static void fun1() {
11             for(int j = 1 ; j < 1000 ; j++){
12                 System.out.println("j = " + j);
13             }
14     }
15
16     private static void fun2() {
17         for(int k = 1 ; k < 1000 ; k++){
18             System.out.println("k = " + k);
19         }
20     }
21 }

2.多线程的例子

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //启动两个线程
 4         new MyThread().start();
 5         new MyThread2().start();
 6
 7         for(int i = 1 ; i < 1000 ; i++){//主进程的for循环必须要等待fun2()执行完毕;
 8             System.out.println("i = " + i);
 9         }
10     }
11 }
1 public class MyThread extends Thread {
2     @Override
3     public void run() {
4         for(int j = 1 ; j < 1000 ; j++){
5             System.out.println("j = " + j);
6         }
7     }
8 }
1 public class MyThread2 extends Thread {
2     @Override
3     public void run() {
4         for(int k = 1 ; k < 1000 ; k++){
5             System.out.println("k = " + k);
6         }
7     }
8 }

3.多线程实现的方式1

线程:在类库中,被封装为:Thread类
 
  1.Thread类就是:程序中的执行线程;
  2.实现方式一:
    1).自定义类,并继承自:Thread;
    2).重写run()方法;
    3).启动:
       A.实例化我们的子类对象;
       B.调用该对象的start()方法,启动线程
 
  伪代码:
  class Thread{
  public void run(){
  System.out.println("a");
  }
  public void start(){
  run();
  }
  }
  class MyThread extends Thread{
  public void run(){
 System.out.println("b");
 }
 }
  main(){
  MyThread t = new MyThread();
  t.start();//启动线程
  }

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //启动线程;
 4         MyThread t1 = new MyThread();
 5         t1.start();//是启动线程的方法;
 6     //    t1.run();//不是启动线程,一般的方法调用;
 7
 8         for(int k = 0;k < 1000 ;k++){
 9             System.out.println("k = " + k);
10         }
11     }
12 }
 1 public class MyThread extends Thread {
 2     //重写run()方法
 3     @Override
 4     public void run() {
 5         //想在单独的线程中执行的代码,写到这里;
 6         for(int i = 0; i < 1000 ;i++){
 7             System.out.println("i = " + i);
 8         }
 9     }
10 }

4.获取线程的名称

Thread类:
  String getName();获取线程名称
 默认的线程名称格式:
  "Thread-索引":
  void setName(String s):设置线程名称

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //可以将一个"线程类",实例化出多个"线程对象",分别启动
 4         MyThread t1 = new MyThread();//默认:Thread-0
 5         MyThread t2 = new MyThread();//默认:Thread-1
 6         MyThread t3 = new MyThread();//默认:Thread-2
 7
 8         t1.setName("梁朝伟");
 9         t2.setName("苗侨伟");
10         t3.setName("曾志伟");
11
12         t1.start();
13         t2.start();
14         t3.start();
15
16     /*    for(int i = 0;i < 100 ;i++){
17             System.out.println(Thread.currentThread().getName() + "-i = " + i);
18         }*/
19
20
21
22     }
23 }
 1 public class MyThread extends Thread {
 2     @Override
 3     public void run() {
 4         for(int i = 0;i < 100; i++){
 5
 6         //    System.out.println(this.getName() + " i = " + i);
 7
 8         }
 9         System.out.println(this.getName() + "我的优先级是:" + this.getPriority());
10     }
11 }

5.线程的优先级

设置线程的优先级:
   1.setPriority(int p):设置优先级。范围:1-10.否则抛异常;
   getPriority():获取优先级;
   2.线程的优先级依赖于"操作系统的调度",需要跟操作系统配合,并不能保证优先级高的线程一定会先执行完毕;
   所以,我们不要依赖于"线程的优先级"去让某个线程先执行完毕!
   3.如果线程内部的业务逻辑很简单,那么线程的优先级将看不出效果;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         MyThread t1 = new MyThread();//Thread-0
 4         MyThread t2 = new MyThread();//Thread-1
 5         MyThread t3 = new MyThread();//Thread-2
 6         MyThread t4 = new MyThread();//Thread-3
 7         MyThread t5 = new MyThread();//Thread-4
 8         MyThread t6 = new MyThread();//Thread-5
 9
10         t1.setPriority(1);
11         t2.setPriority(1);
12         t3.setPriority(1);
13         t4.setPriority(1);
14         t5.setPriority(10);
15
16         t6.setPriority(1);//最高优先级;
17
18         t1.start();
19         t2.start();
20         t3.start();
21         t4.start();
22         t5.start();
23
24         t6.start();
25     }
26 }
 1 public class MyThread extends Thread {
 2     @Override
 3     public void run() {
 4         double sum = 0;
 5         for (int i = 1; i <= 10; i++) {
 6             for (int j = 1; j <= 2000; j++) {
 7                 sum += (Math.E + Math.PI) / i;
 8                 if (j % 200000 == 0) {
 9                     // 让当前线程退回到"就绪"状态,让其它线程有机会执行;
10                     Thread.yield();
11                 }
12             }
13             System.out.println(this.getName() + " i= " + i + " 我的优先级:"
14                     + this.getPriority());
15
16         }
17
18         System.out.println(this.getName() + " 执行完毕!");
19     }
20 }

6.线程休眠_sleep

线程休眠
  public static void sleep(long millis):参数单位:毫秒

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //在主进程,让主进程休眠;
 4         /*for(int i = 0 ;i < 10 ;i++){
 5             try {
 6                 Thread.sleep(1000);
 7             } catch (InterruptedException e){
 8                 e.printStackTrace();
 9             }
10             Date date = new Date();
11             SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日  HH:mm:ss");
12             String str = sdf.format(date);
13             System.out.println(str);
14
15         }*/
16
17         new MyThread().start();
18     }
19 }
 1 public class MyThread extends Thread {
 2     @Override
 3     public void run() {
 4         for(int i = 0 ;i < 10 ;i++){
 5             try {
 6                 Thread.sleep(1000);
 7             } catch (InterruptedException e){
 8                 e.printStackTrace();
 9             }
10             Date date = new Date();
11             SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日  HH:mm:ss");
12             String str = sdf.format(date);
13             System.out.println(str);
14
15         }
16     }
17 }

7.线程加入_join

 1 public class Demo {
 2     public static void main(String[] args) throws InterruptedException {
 3         MyThread t1 = new MyThread();
 4         MyThread t2 = new MyThread();
 5         MyThread t3 = new MyThread();
 6
 7         t1.setName("兵1");
 8         t2.setName("兵2");
 9         t3.setName("兵3");
10
11         t1.start();
12         //让兵1先上,你先杀,完事我再上
13         /*try {
14             t1.join();
15         } catch (InterruptedException e) {
16             e.printStackTrace();
17         }*/
18         t2.start();
19
20         t2.join();
21         t3.start();
22
23     }
24 }
25 public class MyThread extends Thread {
26     @Override
27     public void run() {
28         for(int i = 0;i < 100; i++){
29             System.out.println(this.getName() + " 正在杀怪  " + i);
30         }
31     }
32 }

8.线程礼让_yield

线程的礼让:

yield():让当前线程退回到"就绪状态",同其它线程一样,一起等待操作系统分配资源,
  很可能刚刚yield的线程会立即被重新分配CPU执行;
  调用yield()不保证线程会最后执行完毕;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         MyThread t1 = new MyThread();
 4         MyThread t2 = new MyThread();
 5         MyThread t3 = new MyThread();
 6
 7         t1.setName("章子怡");
 8         t2.setName("汪峰");
 9         t3.setName("撒贝宁");
10
11         t1.start();
12         t2.start();
13         t3.start();
14
15
16     }
17 }
18 public class MyThread extends Thread{
19     @Override
20     public void run() {
21         for(int i = 0;i < 1000; i++){
22             System.out.println(this.getName() + " i = " + i);
23             if(this.getName().equals("汪峰")){
24                 //礼让一下
25                 Thread.yield();
26             }
27         }
28         System.out.println(this.getName() + "--执行完毕!");
29
30     }
31 }

9.后台线程_setDeamon

当主方法结束时,主线程开出的线程仍然继续运行,直到运行完毕;
这个就是:非守护线程;开出的线程不会守护我们的主进程;
可以设置线程为:守护线程:setDeamon(true):它将守护主进程,如果主进程结束,守护线程会跟着结束,
(但不会立即结束,会有个小缓冲);

默认情况下,开出的线程都是:非守护线程;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         MyThread t = new MyThread();
 4         t.setName("兵1");
 5         t.setDaemon(true);//设为守护线程;
 6         t.start();
 7
 8         for(int i = 0;i < 10;i++){
 9             System.out.println("将军杀敌: i = " + i);
10         }
11         System.out.println("将军杀完,收兵!!回家.....");
12     }
13 }
14 public class MyThread extends Thread{
15     @Override
16     public void run() {
17         for(int i = 0;i < 100;i++){
18             System.out.println(this.getName() + " 正在杀敌   i = " + i);
19         }
20     }
21 }

10.线程的中断_stop_interrupt

在主进程中可以结束某个线程:
 
  方式一:stop();(已过时)
  方式二:interrupt()(建议使用):当线程处于:Object--wait()及Thread的--join()以及Thread--sleep()受阻时,
 此方法调用将会导致上述三个方法阻塞时的异常抛出;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         MyThread t = new MyThread();
 4         t.start();
 5
 6         //让主进程等待3秒
 7         System.out.println("主进程等待3秒......");
 8         try {
 9             Thread.sleep(1000 * 3);
10         } catch (InterruptedException e) {
11             e.printStackTrace();
12         }
13         System.out.println("干掉线程:");
14     //    t.stop();
15
16         t.interrupt();
17
18
19     }
20 }
21 public class MyThread extends Thread{
22     @Override
23     public void run() {
24         for(int i = 0;i < 100; i++){
25             try {
26                 Thread.sleep(200);//Thread--sleep()阻塞(Object--wait();Thread-->join())
27             } catch (InterruptedException e) {
28                 //当线程外部对此线程调用interrupt()方法时,会导致这里产生异常。
29                 //可以在这里,结束当前线程;
30
31             //    e.printStackTrace();
32                 System.out.println("外部调用了我的interrupt()方法,我被终止了,拜拜......");
33                 break;
34             }
35             System.out.println(this.getName() + " i= " + i);
36
37         }
38     }
39 }

11.多线程程序实现的方式2

多线程程序实现的方式2:

1.实现Runnable接口;
  2.重写run()方法;
  3.启动线程:
    1).实例化我们自定义类的对象;
    2).实例化一个Thread对象,并用自定义对象做参数;
    3).调用Thread对象的start()

 1 public class Demo {
 2     public static void main(String[] args) {
 3         MyRunnable myRun = new MyRunnable();
 4         new Thread(myRun).start();
 5         for(int k = 0;k < 100 ; k++){
 6             System.out.println(" k = " + k);
 7         }
 8     }
 9 }
10 public class MyRunnable implements Runnable {
11
12     @Override
13     public void run() {
14         for(int i = 0;i < 1000; i++){
15             System.out.println(Thread.currentThread().getName() + " i = " + i);
16         }
17     }
18
19 }

12.继承Thread类的方式卖电影票案例

三个窗口共同享有同一个对象的引用,并且获取同一对象内的数据,此对象,就面临着"并发访问的问题"。
 这种并发性访问会导致数据的不一致性;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.实例化一个票池
 4         TicketPool pool = new TicketPool();
 5         //2.实例化三个窗口线程
 6         MyThread t1 = new MyThread(pool);
 7         MyThread t2 = new MyThread(pool);
 8         MyThread t3 = new MyThread(pool);
 9
10         t1.setName("窗口1");
11         t2.setName("窗口2");
12         t3.setName("窗口3");
13
14         t1.start();
15         t2.start();
16         t3.start();
17
18     }
19 }
20 import java.util.TreeSet;
21
22 public class MyThread extends Thread {
23     //每个线程内部,都要持有一个TicketPool对象,表示几个线程共同抢一个票池的票
24     private TicketPool tp;
25
26     //一个集合,存已抢到的票。为了把票排序,使用TreeSet
27     TreeSet<Integer> set = new TreeSet<>();
28     //通过构造方法赋值
29     public MyThread(TicketPool pool){
30         this.tp = pool;
31     }
32     @Override
33     public void run() {
34         while(true){
35             int ticket = this.tp.getTicket();
36             if(ticket > 0){
37             //    System.out.println(this.getName() + " 抢到票:" + ticket);
38                 set.add(ticket);
39             }else{
40             //    System.out.println("没票了,不抢了!" + this.getName() + "结束!" );
41                 break;
42             }
43         }
44         //总结一下,一共抢到多少张票
45         System.out.println(this.getName() + " 一共抢到:" + this.set.size() + " 张票。明细:" + set);
46     }
47 }
48 public class TicketPool {
49     private int tickets = 100;
50
51     //公有方法,供外部调用:获取一张票
52     public int getTicket(){//窗口1,窗口2
53
54             if(tickets > 0 ){
55                 //窗口1,窗口2
56                 return tickets--;//窗口1--取走:100,窗口2--取走:100 :tickets--
57             }else{
58                 return 0;
59             }
60
61
62     }
63
64 }

13.使用同步解决并发性问题

什么情况下会产生并发性问题:

1.是否是多线程环境:是
2.是否有共享数据:是:TicketPool
3.是否有多条语句操作共享数据:即使:ticket--;这样的一句话都不具有"原子性"

解决并发性问题,在被多线程访问的代码上添加一个关键字:synchronized
语法格式:
synchronized(被锁的对象){
//可能被多个线程并发访问的代码;
 }

被锁的对象:指在这个对象上加锁,也就意味着,当一个线程访问这段代码时,对于"被锁对象"中的其它的
synchronized的代码块或方法,不允许被其它线程访问;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         // 1.实例化一个票池
 4         TicketPool pool = new TicketPool();
 5         // 2.实例化三个窗口线程
 6         MyThread t1 = new MyThread(pool);
 7         MyThread t2 = new MyThread(pool);
 8         MyThread t3 = new MyThread(pool);
 9
10         t1.setName("窗口1");
11         t2.setName("窗口2");
12         t3.setName("窗口3");
13
14         t1.start();
15         t2.start();
16         t3.start();
17     }
18 }
19 import java.util.TreeSet;
20
21 public class MyThread extends Thread {
22     //每个线程内部,都要持有一个TicketPool对象,表示几个线程共同抢一个票池的票
23     private TicketPool tp;
24
25     //一个集合,存已抢到的票。为了把票排序,使用TreeSet
26     TreeSet<Integer> set = new TreeSet<>();
27     //通过构造方法赋值
28     public MyThread(TicketPool pool){
29         this.tp = pool;
30     }
31     @Override
32     public void run() {
33         while(true){
34             int ticket = this.tp.getTicket();
35             if(ticket > 0){
36             //    System.out.println(this.getName() + " 抢到票:" + ticket);
37                 set.add(ticket);
38             }else{
39             //    System.out.println("没票了,不抢了!" + this.getName() + "结束!" );
40                 break;
41             }
42         }
43         //总结一下,一共抢到多少张票
44         System.out.println(this.getName() + " 一共抢到:" + this.set.size() + " 张票。明细:" + set);
45     }
46 }
47 public class TicketPool {
48     private int tickets = 100;
49
50     //公有方法,供外部调用:获取一张票
51     public int getTicket(){//窗口1,窗口2
52         //同步代码块;
53         synchronized (this) {//里面的代码,可能会被多线程访问,加锁;
54             if(tickets > 0 ){
55                 //窗口1,窗口2
56                 return tickets--;//窗口1--取走:100,窗口2--取走:100 :tickets--
57             }else{
58                 return 0;
59             }
60         }
61
62     }
63
64 }

14.JDK5的Lock锁

JDK5之后,提供一种的加锁的方式:Lock(接口):
 
  java.util.concurrent.locks.Lock(接口):
  Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
 
  参考帮助文档:
  使用方式:
  Lock l = new ReentrantLock();
l.lock();//加锁
try {
//被同步的代码;

} finally {
l.unlock();//释放锁

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.实例化一个票池
 4         TicketsPool pool = new TicketsPool();
 5         //2.实例化三个线程,表示三个售票窗口
 6         MyThread t1 = new MyThread(pool);
 7         MyThread t2 = new MyThread(pool);
 8         MyThread t3 = new MyThread(pool);
 9
10         t1.setName("窗口1");
11         t2.setName("窗口2");
12         t3.setName("窗口3");
13
14         //3.启动三个窗口
15         t1.start();
16         t2.start();
17         t3.start();
18     }
19 }
 1 import java.util.TreeSet;
 2
 3 /*
 4  * 此线程代表"窗口"售票线程,此类会被实例化三个对象,表示三个售票窗口;
 5  */
 6 public class MyThread extends Thread {
 7     // 由于每个对象都需要使用同一个票池,所以,都要包含同一个TicketsPool对象
 8     private TicketsPool pool;
 9     // 存已抢到的票的集合.每个售票窗口都有一个独立的集合;
10     TreeSet<Integer> set = new TreeSet<>();
11
12     public MyThread(TicketsPool pool) {
13         this.pool = pool;
14     }
15
16     @Override
17     public void run() {
18         while (true) {
19             int ticket = this.pool.getTicket();
20             if (ticket > 0) {
21                 set.add(ticket);
22             } else {
23                 break;
24             }
25         }
26         System.out.println(this.getName() + " 共抢到:" + this.set.size() + " 张票:"
27                 + set);
28     }
29 }
 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3
 4 /*
 5  * JDK5的Lock锁:
 6  *
 7  * 1.在类的"成员变量"处,实例化一个Lock的子类对象;目的是使此类的所有方法都可以使用此锁;
 8  * 2.在需要加锁的地方按照建议的格式使用:
 9  *             l.lock();//加锁
10  *             try{
11  *
12  *             }finally{
13  *                 l.unlock();//释放锁
14  *             }
15  */
16 public class TicketsPool {
17     private int tickets = 100;
18     private Lock lock = new ReentrantLock();
19     //之前加锁的方式
20     /*
21     public synchronized int getTicket(){
22         if(this.tickets > 0){
23             return this.tickets--;
24         }else{
25             return 0;
26         }
27     }
28     */
29     //Lock锁
30     public  int getTicket(){
31         lock.lock();
32         try{
33             if(this.tickets > 0){
34                 return this.tickets--;
35             }else{
36                 return 0;
37             }
38         }finally{
39             lock.unlock();
40         }
41     }
42 }

15.死锁的现象

实例

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.先实例化两个共享资源
 4         MyClass1 c1 = new MyClass1();
 5         MyClass2 c2 = new MyClass2();
 6
 7         //2.实例化两个线程
 8         MyThread1 t1 = new MyThread1(c1,c2);
 9         MyThread2 t2 = new MyThread2(c1,c2);
10
11         //3.启动
12         t1.start();
13         t2.start();
14
15     }
16 }
17 public class MyClass1 {
18     public synchronized void show1(){
19         System.out.println("MyClass1-->show1()");
20     }
21 }
22 public class MyClass2 {
23     public synchronized void show2(){
24         System.out.println("MyClass2-->show2()");
25     }
26 }
27 public class MyThread1 extends Thread {
28     private MyClass1 c1;
29     private MyClass2 c2;
30
31     public MyThread1(MyClass1 c1 ,MyClass2 c2){
32         this.c1 = c1;
33         this.c2 = c2;
34     }
35
36     @Override
37     public void run() {
38         synchronized (c1) {
39             try {
40                 Thread.sleep(1000);
41             } catch (InterruptedException e) {
42                 e.printStackTrace();
43             }
44             System.out.println("线程1即将访问c2的show2()......");
45             c2.show2();
46             System.out.println("线程1访问c2的show2()结束!");
47         }
48     }
49 }
50 public class MyThread2 extends Thread{
51     private MyClass1 c1;
52     private MyClass2 c2;
53
54     public MyThread2(MyClass1 c1 ,MyClass2 c2){
55         this.c1 = c1;
56         this.c2 = c2;
57     }
58     public void run() {
59         synchronized (c2) {
60             try {
61                 Thread.sleep(1000);
62             } catch (InterruptedException e) {
63                 e.printStackTrace();
64             }
65             System.out.println("线程2即将访问c1的show1()......");
66             c1.show1();
67             System.out.println("线程2访问c1的show1()结束!");
68         }
69     }
70 }

16.生产和消费者(案例)

包子铺卖包子的例子:

 1 import java.util.ArrayList;
 2
 3 public class Demo {
 4     public static void main(String[] args) {
 5         //1.实例化一个包子铺
 6         BaoZiPu bzp = new BaoZiPu();
 7         //2.实例化生产者和消费者线程
 8         SetThread setThread = new SetThread(bzp);
 9         GetThread getThread = new GetThread(bzp);
10
11         //3.启动线程
12         setThread.start();
13         getThread.start();
14
15     }
16 }
17
18
19 import java.util.ArrayList;
20
21 public class BaoZiPu {
22     private ArrayList<String> baoZiList = new ArrayList<>();
23
24     //此方法供"生产者线程"访问
25     public synchronized void setBaoZi(String s){
26         this.baoZiList.add(s);
27     }
28     //此方法供"消费方线程"调用;
29     public synchronized String getBaoZi(){
30         if(this.baoZiList.size() > 0){//取包子
31             String s = this.baoZiList.get(0);//取集合中的第一个元素
32             this.baoZiList.remove(0);//将第一个元素删除。因为包子被取走了。
33             return s;//将包子返回给消费者
34
35         }else{
36             return null;
37         }
38     }
39 }
40
41 public class GetThread extends Thread {
42     private BaoZiPu bzp ;
43     public GetThread(BaoZiPu bzp){
44         this.bzp = bzp;
45     }
46
47     @Override
48     public void run() {
49         while(true){
50             String s = this.bzp.getBaoZi();
51             System.out.println("我兴高采烈的买到了一个:" + s);
52         }
53     }
54 }
55
56
57 public class SetThread extends Thread {
58     private BaoZiPu bzp;
59     public SetThread(BaoZiPu bzp){
60         this.bzp = bzp;
61     }
62     @Override
63     public void run() {
64         while(true){
65             //为了效果明显,让生产方慢点生产
66             try {
67                 Thread.sleep(1);
68             } catch (InterruptedException e) {
69                 e.printStackTrace();
70             }
71             this.bzp.setBaoZi("包子");
72         }
73     }
74 }

17.使用等待和唤醒更改_生产和消费者

此例是"单生产"和"单消费",不适用于"多生产"和"多消费";

注意:
  1.让当前访问的线程等待:Object-->wait();
  唤醒当前等待的线程:Object-->notify()
  notifyAll();
  上述三个方法一定要在同步的方法中使用;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.实例化一个包子铺
 4         BaoZiPu bzp = new BaoZiPu();
 5         //2.实例化生产者和消费者线程
 6         SetThread setThread = new SetThread(bzp);
 7         GetThread getThread = new GetThread(bzp);
 8
 9         //3.启动线程
10         setThread.start();
11         getThread.start();
12
13     }
14 }
15
16 import java.util.ArrayList;
17
18 public class BaoZiPu {
19     private ArrayList<String> baoZiList = new ArrayList<>();
20
21     // 此方法供"生产者线程"访问
22     public synchronized void setBaoZi(String s) {
23         this.baoZiList.add(s);
24         //唤醒所有等待的线程
25         notifyAll();//使用notify()也可以;
26     }
27
28     // 此方法供"消费方线程"调用;
29     public synchronized String getBaoZi() {
30         /*
31          * if(this.baoZiList.size() > 0){//取包子 String s =
32          * this.baoZiList.get(0);//取集合中的第一个元素
33          * this.baoZiList.remove(0);//将第一个元素删除。因为包子被取走了。 return s;//将包子返回给消费者
34          *
35          * }else{ return null; }
36          */
37         if (this.baoZiList.size() == 0) {
38             try {
39                 this.wait();//让当前访问的线程等待......
40             } catch (InterruptedException e) {
41                 e.printStackTrace();
42             }
43         }
44
45         //为用户取包子
46         String s = this.baoZiList.get(0);
47         this.baoZiList.remove(0);
48         return s;
49     }
50 }
51
52 public class GetThread extends Thread {
53     private BaoZiPu bzp ;
54     public GetThread(BaoZiPu bzp){
55         this.bzp = bzp;
56     }
57
58     @Override
59     public void run() {
60         while(true){
61             String s = this.bzp.getBaoZi();
62             System.out.println("我兴高采烈的买到了一个:" + s);
63         }
64     }
65 }
66
67 public class SetThread extends Thread {
68     private BaoZiPu bzp;
69     public SetThread(BaoZiPu bzp){
70         this.bzp = bzp;
71     }
72     @Override
73     public void run() {
74         while(true){
75             //为了效果明显,让生产方慢点生产
76             try {
77                 Thread.sleep(1);
78             } catch (InterruptedException e) {
79                 e.printStackTrace();
80             }
81             this.bzp.setBaoZi("包子");
82         }
83     }
84 }
时间: 2024-10-01 08:48:51

java--多线程(1)--黑马程序员的相关文章

黑马程序员——java基础——多线程

 黑马程序员--java基础--多线程 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 线程:就是进程中的一个独立的控制单元.线程在控制着进程的执行.一个进程中至少有一个线程. 一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区.自己的变量.

黑马程序员---Java多线程

---------------------- Android开发.java培训.期待与您交流! ---------------------- 线程与进程是程序运行中体现的两个名词,它包含这不同的程序域.进程指的是一个正在运行的程序,如:360,QQ运行时就是不同的两个进程.当你打开windows任务管理器时,看到的每个进程就是此时windows中正在运行的程序.线程则就是进程中的一个个独立的控制单元,线程控制着进程的执行,也就是说每个正在运行的程序中就包括着很多的线程. 主线程:Java虚拟机运

黑马程序员–Java之多线程09

黑马程序员–Java之多线程09 一.线程和进程 在Java中,并发机制非常重要,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程.多线程就是指一个应用程序中有多条并发执行的线索,每条线索都被称作一个线程,它们会交替执行,彼此间可以进行通信.多线程是非常复杂的机制,在每个操作系统中的运行方式也存在差异,window操作系统是多任务操作系统,它以进程为单位.一个进程是一个包含有自身地址的程序,每个独立执行的程序都称为进程,也就是正在执行的程序.系统

黑马程序员——java多线程基础知识1

多线程 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行.jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为主线程.虚拟机至少也有两个线程,一个主线程执行,另一个负

黑马程序员——Java多线程基础知识2

多线程协同 线程间的通讯:我们对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤.但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,我用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必

黑马程序员——Java多线程

多线程基础知识 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行..jvm启动的时候会有一个进程就叫做java.exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为住线程.虚拟机至少也有两个线程,一个主线程执行

黑马程序员——Java基础知识之多线程协同

多线程协同 线程间的通讯:对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤,但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必须用在

黑马程序员之Java多线程学习

android培训  java培训 期待与您交流! 这一篇文章主要关于java多线程,主要还是以例子来驱动的.因为讲解多线程的书籍和文章已经很多了,所以我也不好意思多说,呵呵.大家可以去参考一些那些书籍.我这个文章主要关于实际的一些问题.同时也算是我以后复习的资料吧,.呵呵大家多多指教. 同时希望多结交一些技术上的朋友.谢谢. -------------------------------------------------------------------------------------

黑马程序员___多线程小结

----------- android培训.java培训.java学习型技术博客.期待与您交流! --------- 进程和线程 进程是正在进行中的程序,指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程. Java程序的进程里有几个线程:主线程, 垃圾回收线程(后台线程) 线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据.多线程:在同一个进程中同时运行的多个任务;一个进程至少有一个线程,为了提高效率,可以在一个进程中

黑马程序员_多线程

------- android培训.java培训.期待与您交流! ---------- 多线程1.进程: 正在运行的程序所占有的内存空间,叫做进程. 线程: 一个应用程序中的子程序,对于CPU,子程序可以有一条独立的执行路径,称为线程. 线程特点:依靠一个应用程序,对于其他子程序,独立被CPU执行的2.多线程的好处: 充分利用CPU的资源,程序的同时运行,提高效率3.java中线程创建的两种方法: 第一种: 定义类继承Thread class extends Thread 重写Thread中的r