zoukankan      html  css  js  c++  java
  • 线程协作

     

    线程通信

    应用场景:生产者和消费者问题

    这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。

    在生产者和消费者问题中,仅有synchronized是不够的。synchronized可阻止并发更新同一个共享资源,实现了同步,但synchronized不能用来实现不同线程之间的消息传递(通信)。

    Java中提供了几个方法解决线程之间的通信问题:

    ①wait()     表示线程会一直等待,直到其他线程通知,与sleep不同,会释放锁

    ②wait(long timeout)  指定等待的毫秒数

    ③notify()   唤醒一个处于等待状态的线程

    ④notifyAll()  唤醒同一个对象上所有调用wait方法的线程,优先级别高的线程优先调度

    均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常IIIegalMonitorStateException

    问题解决方式1

    并发协作模型“生产者/消费者问题”---管程法

    · 生产者:负责生产数据的模块(可能是方法、对象、线程、进程);

    · 消费者:负责处理数据的模块(可能是方法、对象、线程、进程);

    · 缓冲区:消费者不能直接使用生产者的数据,他们之间有个“缓冲区”。

    生产者将生产好的数据放入缓冲区,消费者从缓冲区中拿出数据

    package com.wang.ssynchronized;

    //测试生产者/消费者问题---利用缓冲区解决(管程法)

    //需要有生产者、消费者、产品、缓冲区
    public class TestProCus {
       public static void main(String[] args) {
        SynContainer container=new SynContainer();

        new Productor(container).start();
        new Consumer(container).start();
      }
    }
    //生产者
    class Productor extends Thread{

       SynContainer container;

       public Productor(SynContainer container){
           this.container=container;
      }

       //需要生产方法

       @Override
       public void run() {
           for (int i = 0; i < 100; i++) {
               container.push(new Chicken(i));
               System.out.println("生产了"+i+"只鸡");
          }
      }
    }
    //消费者
    class Consumer extends Thread{
       SynContainer container;

       public Consumer(SynContainer container){
           this.container=container;
      }
       //消费

       @Override
       public void run() {
           for (int i = 0; i < 100; i++) {
               System.out.println("消费了"+container.pop().id+"只鸡");
          }
      }
    }
    //产品
    class Chicken{
       int id;//产品编号

       public Chicken(int id) {
           this.id = id;
      }
    }
    //缓冲区
    class SynContainer{
       //需要一个容器大小
       Chicken[] chickens=new Chicken[10];
       //容器计数器
       int count=0;
       //需要生产者放入产品
       public synchronized void push(Chicken chicken){
           //如果容器满了,就需要等待消费者消费
           if(count==chickens.length){
               //通知消费者消费,生产者等待
               try {
                   this.wait();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           //如果没有满,就需要放入产品
           chickens[count]=chicken;
           count++;

           //可以通知消费者消费了
               this.notifyAll();
      }
       //消费者消费产品
       public synchronized Chicken pop(){
           //判断能否消费
           if (count==0){
               //等待生产者生产,消费者等待
               try {
                   this.wait();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           //如果可以消费
           count--;
           Chicken chicken=chickens[count];

           //通知生产者生产
           this.notifyAll();
           return chicken;
      }
    }

    解决方式2

    并发协作模型“生产者/消费者问题”---信号灯法

      package com.wang.ssynchronized;

    //测试生产者/消费者问题----信号灯法,标志位解决
    public class TestPC2 {
       public static void main(String[] args) {
           TV tv=new TV();
           new Player(tv).start();
           new Watcher(tv).start();
      }
    }
    //生产者--演员
    class Player extends Thread{
       TV tv;
       public Player(TV tv){
           this.tv=tv;
      }

       @Override
       public void run() {
           for (int i = 0; i < 20; i++) {
               if (i%2==0){
                   this.tv.play("快乐大本营播放中");
              }else {
                   this.tv.play("抖音记录美好生活");
              }
          }
      }
    }
    //消费者--观众
    class Watcher extends Thread{
       TV tv;
       public Watcher(TV tv){
           this.tv=tv;
      }

       @Override
       public void run() {
           for (int i = 0; i < 20; i++) {
               tv.watch();
          }
      }
    }
    //产品--节目
    class TV{
       //演员表演的时候,观众等待 T
       //观众观看的时候,演员等待 F
       String voice;//表演的节目

       boolean flag=true;
       //表演
       public synchronized void play(String voice){
           if (!flag){
               try {
                   this.wait();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           System.out.println("演员表演了"+voice);
           //通知观众观看
           this.notifyAll();//通知唤醒
           this.voice=voice;
           this.flag=!this.flag;//取反
      }
       //观看
       public synchronized void watch(){
           if (flag){
               try {
                   this.wait();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           System.out.println("观众观看了"+voice);
           //通知演员表演
           this.notifyAll();
           this.flag=!this.flag;
      }
    }

    使用线程池

    背景:经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大

    思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁的创建销毁、实现重复利用。

    好处:提高响应速度(减少了创建新线程的时间)

               降低资源消耗(重复利用线程池中线程,不需要每次都创建)

               便于线程管理

                      corePoolSize:核心池的大小

                     maximumPoolSize:最大线程数

                     keepAliveTime:线程没有任务时最多保持多长时间后会终止

    JDK5.0起提供了线程池相关API:ExecutorService和Executors

    ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

          void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable

          <T> Future <T> submit(Callable<T> task):执行任务,有返回值,一般用来执行Callable

          void shutdown():关闭连接池

    Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

    package com.wang.threadpool;

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    //测试线程池
    public class TestPool {
       public static void main(String[] args) {
           //创建线程池
           //newFixedThreadPool 参数为:线程池大小
           ExecutorService service= Executors.newFixedThreadPool(10);

           //执行Runnable接口的实现类
           service.execute(new MyThread());
           service.execute(new MyThread());
           service.execute(new MyThread());
           service.execute(new MyThread());

           //关闭连接
           service.shutdownNow();
      }
    }
    class MyThread implements Runnable{
       @Override
       public void run() {

               System.out.println(Thread.currentThread().getName());

      }
    }

     

     

     

     

  • 相关阅读:
    js循环
    js对象
    实现checkebox全选取消操作
    js数组
    jquery记忆笔记
    js选择checkbox值,组织成key-value形式,传值到后台
    ES6常用语法,面试应急专用!
    Win10 系统运行VsCode出现白屏的问题(亲测有效)
    command failed: npm install --loglevel error --registry=https://registry.npm 用vue-cli 4.0 新建项目总是报错
    MODULE BUILD FAILED: ERROR: COULDN’T FIND PRESET “ES2015” RELATIVE TO DIRECTORY
  • 原文地址:https://www.cnblogs.com/wyj96/p/11979745.html
Copyright © 2011-2022 走看看