• Java 基础复习 Day 22


    Java 基础复习 Day 22

    (多线程 4)

    1 等待与唤醒机制

    1.1 线程间通信:

    • 概念:多个线程在处理同一个资源,但是处理的动作(各线程任务不同)

      举例:(图片来自某网课,如有侵权联系删除)

    在这里插入图片描述

    • 处理线程间通信的原因:

      由于要处理同一份资源,为了避免对同一资源的争夺,那么就需要对多线程之间进行协调,保证能够达到多线程正确处理同一个资源

      (比如线程A生产完包子之后,线程B才能去消费)

    1.2 等待唤醒机制

    • 概念 :这是多个线程之间的一种协作机制,在多线程之间有通信时, 通过使用wait notify等方法让线程有效并正确的利用同一个资源。

    • 具体体现:在吃包子的例子中等待唤醒机制具体如下:(图片来自某网课,如有侵权联系删除)

    在这里插入图片描述

    • 注意事项

      1. 当某线程从waiting状态被唤醒时, 也有可能不会立即执行,需要看此时cpu是否空闲,也就是看此时就要看能不能获得锁,如果能获取锁,可执行进入Runnable状态,如果cpu不空闲,不能获取锁,那么该线程可能进入blocked状态。

      2. wait方法和notify方法在调用时, 应该使用同一个锁对象:这样对应的锁对象会notify使用同一个锁对象调用的wait方法后的线程

      3. wait方法和notify方法是属于Object类的(锁对象是可以是任意对象,而任意对象的所属类都是Object的子类)

      4. wait方法和notify方法必须要在同一个代码块或者是同步代码函数中使用,因为:必须要通过锁对象调用这个方法

    • 等待唤醒案例具体分析:(图片来自某网课,如有侵权联系删除)

    在这里插入图片描述

    • 等待唤醒机制代码实现(例子也来自某网课)

      生产者线程:

      public class Consumer extends Thread{
          private Baozi bz;
      
          public Consumer(Baozi bz) {
              this.bz = bz;
          }
      
          @Override
          public void run() {
              while (true){
                  synchronized (bz){
                      if (bz.flag==false){
                          try {
                              bz.wait();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          //被唤醒后就吃包子
                          System.out.println("The consumer is eating baozi with: " + bz.pi + bz.xian);
                          bz.flag = false;
                          bz.notify();
                          System.out.println("The baozi with: "+bz.pi + bz.xian + " has been eaten all, please produce one more");
                          System.out.println("==========================================");
                      }
                  }
              }
      
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29

      消费者线程:

      public class Consumer extends Thread{
          private Baozi bz;
      
          public Consumer(Baozi bz) {
              this.bz = bz;
          }
      
          @Override
          public void run() {
              while (true){
                  synchronized (bz){
                      if (bz.flag==false){
                          try {
                              bz.wait();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          //被唤醒后就吃包子
                          System.out.println("The consumer is eating baozi with: " + bz.pi + bz.xian);
                          bz.flag = false;
                          bz.notify();
                          System.out.println("The baozi with: "+bz.pi + bz.xian + " has been eaten all, please produce one more");
                          System.out.println("==========================================");
                      }
                  }
              }
      
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29

      测试类:

      public class Demo12Main {
          public static void main(String[] args) {
              //创建包子对象,作为包子铺线程和吃货线程的锁对象作为初始化参数通过构造方法传进去
              Baozi baozi = new Baozi();
              //创建消费者线程和包子线程
              new Consumer(baozi).start();
              new BaoziPu(baozi).start();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      测试结果:

      baozipu is making baozi with: thickchicken
      baozi have been made ok with: thickchicken You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thickchicken
      The baozi with: thickchicken has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thinbeef
      baozi have been made ok with: thinbeef You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thinbeef
      The baozi with: thinbeef has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thickchicken
      baozi have been made ok with: thickchicken You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thickchicken
      The baozi with: thickchicken has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thinbeef
      baozi have been made ok with: thinbeef You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thinbeef
      The baozi with: thinbeef has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thickchicken
      baozi have been made ok with: thickchicken You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thickchicken
      The baozi with: thickchicken has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thinbeef
      baozi have been made ok with: thinbeef You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thinbeef
      The baozi with: thinbeef has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thickchicken
      baozi have been made ok with: thickchicken You may start eating!
      ++++++++++++++++++++++++++
      The consumer is eating baozi with: thickchicken
      The baozi with: thickchicken has been eaten all, please produce one more
      ==========================================
      baozipu is making baozi with: thinbeef
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43

    1. 线程池

      • 线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复循环利用,省去了频繁创建线程对象的操作,无需因为反复创建销毁线程而浪费系统资源。

      • 线程池的工作原理如下图所示:
        在这里插入图片描述

      • Java在JDK1.5以后就提供了线程池的工厂类

        • java.lang.Object

          • java.util.concurrent.Executors

            static ExecutorService newFixedThreadPool(int nThreads) 创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。

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

            返回值:ExecutorService:返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口来接收(面向接口)用来获取线程,调用start开始执行线程。

            通过ExecutorService调用Future submit(Runnable task)来提交一个Runnable用与执行

            • 提交值返回任务以执行,并返回代表任务待处理结果的Future。未来的get方法将在成功完成后返回任务的结果。

              如果您想立即阻止等待任务,您可以使用result = exec.submit(aCallable).get();格式的result = exec.submit(aCallable).get();

              注意: Executors类包括一组方法,可以将一些其他常见的类似对象的对象,例如PrivilegedAction转换Callable表单,以便它们可以提交。

              • 参数类型

                T - 任务结果的类型

              • 参数

                task - 提交的任务

              • 结果

                一个未来的代表,待完成任务

              • 异常

                RejectedExecutionException - 如果任务无法安排执行

                NullPointerException - 如果任务为空

            void shutdown()

            启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。如果已经关闭,调用没有额外的作用。

            此方法不等待以前提交的任务完成执行。 使用awaitTermination做到这一点。

      • 线程池的使用步骤:(未完待续)

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

    3. 创建一个类来实现Runnable方法 ,重写run方法

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

    5. 调用ExecutorService的shutdown,但是不建议使用,因为会销毁线程。

      代码实现:

      public static void main(String[] args) {
              //1.使用线程池的工厂类Executors 里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
              ExecutorService es = Executors.newFixedThreadPool(3);
              //3,调用ExecutorService中的submit方法,传递线程任务(实现类),开启线程执行run方法
              es.submit(new RunnableImpl());//pool-1-thread-2create a new thread
              //线程池会一直开启,使用完了线程,会自动把线程归还给线程池
              es.submit(new RunnableImpl());//pool-1-thread-1create a new thread
              es.submit(new RunnableImpl());//pool-1-thread-2create a new thread
              es.submit(new RunnableImpl());//pool-1-thread-3create a new thread
              //4.调用ExecutorService的shutdown,但是不建议使用,因为会销毁线程。
              es.shutdown();
              //销毁了所有线程后,线程池里就没有线程,因此执行下列语句就会报错。
              es.submit(new RunnableImpl());
              //Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@330bedb4 rejected from java.util.concurrent.ThreadPoolExecutor@2503dbd3[Shutting down, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 1]
              //	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
              //	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
              //	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
              //	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
              //	at com.kou.thread.demo12.Demo01ThreadPool.main(Demo01ThreadPool.java:19)
          }
      //2.创建一个类来实现Runnable方法 ,重写run方法
      public class RunnableImpl implements Runnable{
          @Override
          public void run() {
              System.out.println(Thread.currentThread().getName()+"create a new thread");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
  • 相关阅读:
    将数组拆分成斐波那契序列
    盘点NFT史上令人难忘的跑路大王
    arm处理器IO口驱动代码编写与测试(bcm2835)
    企业运维实践-Nginx使用geoip2模块并利用MaxMind的GeoIP2数据库实现处理不同国家或城市的访问最佳实践指南...
    学习JFinal
    Nginx 默认location index设置网站的默认首页
    学习MySQL的第六天:事务(基础篇)
    深度学习-卷积神经网络-ResNET
    java 对多维数组的工具类(比如遍历多维数组工具类)
    java计算机毕业设计-公益劳动招募管理系统-源码+数据库+系统+lw文档+mybatis+运行部署
  • 原文地址:https://blog.csdn.net/karenkou/article/details/126252917