UC并发编程学习笔记(简单易懂)3

简介: UC并发编程学习笔记(简单易懂)

5:读写锁(ReadWriteLock)

9fe4732a00104710ad830cbe2e3199f7.png

5.1 使用

package main;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* 独占锁(写锁) 一次只能被一个线程占有
* 共享锁(读锁) 多个线程可以同时占有
* ReadWriteLock
* 读 - 读 可以共存
* 读 - 写 不能共存
* 写 - 写 不能共存
* */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        //MyCache myCache =new MyCache();
        MyCacheLock myCache =new MyCacheLock();
        //写入
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        //读取
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}
class MyCacheLock{
    private volatile Map<String,Object> map = new HashMap<>();
    //读写锁:更加细粒度的控制
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //存,写 的时候,只希望同时只有一个线程写
    public  void  put(String key,Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"写入"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }
    //取,读  所有人都可以读
    public  void  get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取"+key);
            map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}
class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    //存,写
    public  void  put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"写入"+key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()+"写入OK");
    }
    //取,读
    public  void  get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
        map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取OK");
    }
}
打印结果:
1写入1
1写入OK
2写入2
2写入OK
3写入3
3写入OK
4写入4
4写入OK
5写入5
5写入OK
2读取2
2读取OK
3读取3
3读取OK
5读取5
5读取OK
1读取1
4读取4
4读取OK
1读取OK

6:阻塞队列

6.1:队列

d1cbdfc5fd804b1c95ab9d6a23011c99.png

队列(FIFO)先进先出。

写入:如果队列满了,就必须阻塞等待。

读取:如果队列是空的,必须阻塞,等待生产,从而读取消息。

f72419cd0cc04193bd83be46620c7320.png

dbbf90fb838b4f08b77a24621c25217d.png

如下图所示:

d912ea9e551f43d3b4ea35a057a6cb3b.png

6.2 :四组API

6.2.1:抛出异常

添加:add()

移除:remove()

判断队首:element()

public class FIFO {
   public static void main(String[] args) {
      say();
   }
   public static void say(){
      ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
      System.out.println(blockingQueue.add("a"));
      System.out.println(blockingQueue.add("b"));
      System.out.println(blockingQueue.add("c"));
      //Exception in thread "main" java.lang.IllegalStateException: Queue full
      //System.out.println(blockingQueue.add("d"));
      System.out.println(blockingQueue.remove());
      System.out.println(blockingQueue.remove());
      System.out.println(blockingQueue.remove());
      //Exception in thread "main" java.util.NoSuchElementException
      //System.out.println(blockingQueue.remove());
   }
}

6.2.2:有返回值,不会抛出异常

添加:offer()

移除:poll()

判断队首:peek()

public class FIFO {
   public static void main(String[] args) {
      say2();
   }
   public static void say2(){
      ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
      //存
      System.out.println(blockingQueue.offer("a"));
      System.out.println(blockingQueue.offer("b"));
      System.out.println(blockingQueue.offer("c"));
      System.out.println(blockingQueue.offer("d"));
      //移除
      System.out.println(blockingQueue.poll());
      System.out.println(blockingQueue.poll());
      System.out.println(blockingQueue.poll());
      System.out.println(blockingQueue.poll());
   }
}
打印:
true
true
true
false
a
b
c
null

6.2.3:阻塞等待

取:put()

移除:take()

public class FIFO {
   public static void main(String[] args) throws InterruptedException {
      say3();
   }
   public static void say3() throws InterruptedException {
      //队列大小
      ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
      blockingQueue.put("a");
      blockingQueue.put("b");
      blockingQueue.put("c");
      //队列没有位置了,第四个一直阻塞
      //blockingQueue.put("d");
      System.out.println(blockingQueue.take());
      System.out.println(blockingQueue.take());
      System.out.println(blockingQueue.take());
      // 队列中没有元素了,第四个一直阻塞
      //System.out.println(blockingQueue.take());
   }
}

6.2.4:超时等待

public class FIFO {
   public static void main(String[] args) throws InterruptedException {
      say4();
   }
   public static void say4() throws InterruptedException {
      ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
      System.out.println(blockingQueue.offer("a"));
      System.out.println(blockingQueue.offer("b"));
      System.out.println(blockingQueue.offer("c"));
      System.out.println(blockingQueue.offer("d",2, TimeUnit.SECONDS));
      System.out.println(blockingQueue.poll());
      System.out.println(blockingQueue.poll());
      System.out.println(blockingQueue.poll());
      System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
   }
}

6.2.5 总结

方法摘要
ArrayBlockingQueue(int capacity) 创建具有给定(固定)容量和默认访问策略的 ArrayBlockingQueue
boolean add(E e) 在插入此队列的尾部,如果有可能立即这样做不超过该队列的容量,返回指定的元素 true成功时与抛出 IllegalStateException如果此队列已满。
boolean remove(Object o) 从该队列中删除指定元素的单个实例(如果存在)。
boolean offer(E e) 如果可以在不超过队列容量的情况下立即将其指定的元素插入该队列的尾部,则在成功时 false如果该队列已满,则返回 true
boolean offer(E e, long timeout, TimeUnit unit) 在该队列的尾部插入指定的元素,等待指定的等待时间,以使空间在队列已满时变为可用
E poll() 检索并删除此队列的头,如果此队列为空,则返回 null 。
E poll(long timeout, TimeUnit unit) 检索并删除此队列的头,等待指定的等待时间(如有必要)使元素变为可用
void put(E e) 在该队列的尾部插入指定的元素,如果队列已满,则等待空间变为可用
E take() 检索并删除此队列的头,如有必要,等待元素可用
E peek() 检索但不删除此队列的头,如果此队列为空,则返回 null

6.3: SynchronousQueue(同步队列)

public class 同步队列 {
   public static void main(String[] args) {
      BlockingQueue<String> queue = new SynchronousQueue<>();
      new Thread(()->{
         try {
            System.out.println(Thread.currentThread().getName()+"执行了a操作");
            queue.put("a");
            System.out.println(Thread.currentThread().getName()+"执行了b操作");
            queue.put("b");
            System.out.println(Thread.currentThread().getName()+"执行了c操作");
            queue.put("c");
         } catch (InterruptedException e) {
            throw new RuntimeException(e);
         }
      },"A").start();
      new Thread(()->{
         try {
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName()+"读取了====a操作");
            queue.take();
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName()+"读取了====b操作");
            queue.take();
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName()+"读取了====c操作");
            queue.take();
         } catch (InterruptedException e) {
            throw new RuntimeException(e);
         }
      },"B").start();
   }
}
打印结果:
A执行了a操作
B读取了====a操作
A执行了b操作
B读取了====b操作
A执行了c操作
B读取了====c操作

7:线程池

三大方法,7大参数,4种拒绝策略

ac9ba5c1eed04ac3b298762cd378aadb.png

7.1 线程池的好处

1. 降低资源的消耗

2. 提高响应的速度

3. 方便管理

线程复用,可以控制最大并发数,管理线程。

7.1.1  3大方法

public class pool {
   public static void main(String[] args) {
      ExecutorService threadPool = Executors.newCachedThreadPool();// 缓存线程池(遇强则强)
      ExecutorService threadPool2 = Executors.newFixedThreadPool(6);//固定线程池大小
      ExecutorService threadPool3 = Executors.newSingleThreadExecutor();//单一线程
      try {
         for (int i = 0; i < 100; i++) {
            threadPool.execute(()->{
               System.out.println(Thread.currentThread().getName());
            });
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      } finally {
         threadPool.shutdown();
      }
   }
}

7.1.2  7大参数

ThreadPoolExecutor

构造方法 :

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

创建一个新的 ThreadPoolExecutor与给定的初始参数。

参数
corePoolSize - (核心线程数)即使空闲时仍保留在池中的线程数,除非设置 allowCoreThreadTimeOut
maximumPoolSize - 池中允许的最大线程数
keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大时间。
unit - keepAliveTime参数的时间单位
workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存execute方法提交的Runnable任务。(阻塞队列)
threadFactory - 执行程序创建新线程时使用的工厂(线程工厂)
handler - 执行被阻止时使用的处理程序,因为达到线程限制和队列容量(拒绝策略)

91affb0345b6434699c74f080dd53256.png

 7.1.2  四种拒绝策略

RejectedExecutionHandler
ThreadPoolExecutor.AbortPolicy 被拒绝的任务的处理程序,抛出一个 RejectedExecutionException 。(银行满了,还有人进来,不处理这个人的,抛出异常)
ThreadPoolExecutor.CallerRunsPolicy 一个被拒绝的任务的处理程序,直接在 execute方法的调用线程中运行被拒绝的任务,除非执行程序已被关闭,否则这个任务被丢弃。(哪来回哪去)
ThreadPoolExecutor.DiscardOldestPolicy 被拒绝的任务的处理程序,丢弃最旧的未处理请求,然后重试 execute ,除非执行程序被关闭,在这种情况下,任务被丢弃。
ThreadPoolExecutor.DiscardPolicy 被拒绝的任务的处理程序静默地丢弃被拒绝的任务

7.1.2.1  代码示例:

/**
 * new ThreadPoolExecutor.AbortPolicy()  银行满了,还有人进来,不处理这个人的,抛出异常)
 * new ThreadPoolExecutor.CallerRunsPolicy()      哪来的回哪去
 * new ThreadPoolExecutor.DiscardOldestPolicy()   队列满了不会抛出异常
 * new ThreadPoolExecutor.DiscardOldestPolicy()   队列满了。尝试去跟第一个线程竞争。如果没竞争过,还是回丢弃任务
 *                                                不会抛出异常
 */
public class newPool {
   public static void main(String[] args) {
      ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2,5,3,
              TimeUnit.SECONDS,
              new LinkedBlockingQueue<>(3),
              Executors.defaultThreadFactory(),
              new ThreadPoolExecutor.DiscardOldestPolicy());
      try {
         //最大承载:Queue + max = 5 + 3 = 8
         //超过RejectedExecution
         for (int i = 0; i < 9  ; i++) {
            poolExecutor.execute(()->{
               System.out.println(Thread.currentThread().getName());
            });
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      } finally {
         poolExecutor.shutdown();
      }
   }
}

8:了解CPU密集型和IO密集型(池的大小)

package main;
import java.util.concurrent.*;
public class ExecutorServiceDemo {
    public static void main(String[] args) {
        /*
        * 最大线程到底该如何定义
        * 1.CPU密集型,几核,最大线程就是几,可以保持CPU的效率最高
        * 2.IO密集型  大于你程序中十分耗IO的线程
        * */
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),
                3,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        try {
            //最大承载:Queue + max
            //超过RejectedExecution
            for (int i = 0; i < 9; i++) {
                //使用线程池之后,使用线程池来创建线程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" : ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}
目录
相关文章
|
Web App开发 编解码 前端开发
面试题22:如何测试Web浏览器的兼容性?
面试题22:如何测试Web浏览器的兼容性?
753 3
|
人工智能 自然语言处理 搜索推荐
6个好用的AI写作工具合集,各种AI写作软件类型超全整理!
AI生成营销文案、生成文章标题、改写润色内容、写作素材搜集...好用的AI写作工具有哪些?
6个好用的AI写作工具合集,各种AI写作软件类型超全整理!
|
7月前
|
机器学习/深度学习 人工智能 算法
【果蔬识别系统】Python+深度学习+人工智能+算法模型+图像识别+2026原创
【果蔬识别系统】Python+深度学习+人工智能+算法模型+图像识别+2026原创
321 1
【果蔬识别系统】Python+深度学习+人工智能+算法模型+图像识别+2026原创
|
7月前
|
SQL 分布式计算 资源调度
驯服数据巨兽:Hadoop如何重塑大数据的黄金时代
本文系统阐述Hadoop生态的演进逻辑:从应对数据爆炸催生的分布式架构,到HDFS、MapReduce、YARN等核心组件原理;涵盖Hive、HBase、Kafka、ZooKeeper等关键工具,以及Iceberg/Hudi数据湖革命、Kerberos安全体系与云原生融合趋势。全景展现“黄色大象”如何由单一体系蜕变为现代数据基础设施的无形基石。(239字)
830 2
|
人工智能 算法 开发者
2025年高教社杯E题——AI 辅助智能体测全国大学生数学建模(思路、代码、论文)
2025年高教社杯E题——AI 辅助智能体测全国大学生数学建模(思路、代码、论文)
1014 1
|
JSON API 数据格式
借助电商 API,多平台客户评价一键抓取
在电商竞争激烈的环境下,客户评价对消费者决策至关重要。本文介绍如何利用电商平台 API(如 Amazon、eBay、淘宝等)一键抓取多平台客户评价,提升数据收集效率,支持情感分析与市场趋势预测。通过 Python 示例代码,讲解 API 请求构建、多平台整合及数据处理方法,助力商家实现数据驱动的产品优化与市场响应。
|
人工智能 自然语言处理 IDE
通义灵码你问我答:看看 5 月上线了哪些新功能?
通义灵码5月升级了智能问答(Ask)模式至Agentic模式,支持自主调用工程感知和网络检索工具,使开发者互动更贴合工程场景。新增行间会话(Inline Chat)与行间建议预测(NES)功能,大幅提升代码修改效率。同时发布AI IDE——Lingma IDE,全面集成智能编码能力,开箱即用,无需额外插件。此外,还优化了上下文文件添加体验及其他多项功能,进一步提升开发效率和用户体验。
|
人工智能 编解码 自然语言处理
Aria-UI:港大联合 Rhymes AI 开源面向 GUI 智能交互的多模态模型,整合动作历史信息实现更加准确的定位
Aria-UI 是香港大学与 Rhymes AI 联合开发的多模态模型,专为 GUI 智能交互设计,支持高分辨率图像处理,适用于自动化测试、用户交互辅助等场景。
900 11
Aria-UI:港大联合 Rhymes AI 开源面向 GUI 智能交互的多模态模型,整合动作历史信息实现更加准确的定位
|
缓存 负载均衡 安全
什么是CDN服务
CDN(内容分发网络)是全球分布的服务器网络,旨在加速互联网内容的传输。它通过将内容缓存至靠近用户的服务器,减少延迟,提升访问速度与性能,同时实现负载均衡、减轻源服务器压力并提供安全防护。广泛应用于网站加速、视频直播等领域,优化用户体验。
12666 5
|
网络协议 Linux 数据安全/隐私保护
【Zookeeper】基于3台linux虚拟机搭建zookeeper集群(一)
【Zookeeper】基于3台linux虚拟机搭建zookeeper集群
773 1
【Zookeeper】基于3台linux虚拟机搭建zookeeper集群(一)