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浏览器的兼容性?
607 3
|
1月前
|
人工智能 弹性计算 机器人
零技术也能玩转龙虾AI!OpenClaw(Clawdbot)保姆级部署流程(阿里云/本地+集成QQ机器人+免费API配置)
2026年,OpenClaw(原Clawdbot)凭借开源免费、功能灵活、可扩展性强的优势,成为AI自动化领域的“国民级工具”。它打破了传统AI“只说不做”的局限,既能接管电脑完成文件整理、报表生成等重复任务,更能集成QQ实现智能交互——自动回复消息、管理群聊、定时提醒,甚至通过QQ远程操控设备,成为个人和小团队的“全能助手”。
579 1
|
23天前
|
存储 安全 Java
别让你的 Java 应用裸奔!OWASP Top10 全漏洞原理、复现与一站式防护方案
本文详解Java应用十大安全风险(OWASP Top10),涵盖失效访问控制、加密失效、注入攻击等核心漏洞的原理、复现代码及防护方案,结合Spring生态最佳实践,助力开发者构建高安全性企业级系统。
316 1
|
28天前
|
前端开发 API 语音技术
从零搭建一个免费的文本转语音在线工具(基于 Python3 + Edge TTS)
最近有个需求,需要把一段文字转换成语音,找了几个在线工具,要么收费,要么有水印,要么音质惨不忍睹。后来发现微软 Edge 浏览器的 TTS(Text-to-Speech)服务音质非常好,而且免费开放使用。于是动手写了一个在线工具,分享给大家。
348 1
|
2月前
|
存储 人工智能 云计算
2026年OpenClaw(Clawdbot)阿里云计算巢一键部署+本地搭建超简单流程,零基础也能上手
OpenClaw的核心价值的在于,它并非单纯的聊天机器人,而是一款能自主执行任务的“数字员工”,可通过自然语言指令完成文件处理、跨工具协同、代码辅助、知识库搭建等各类流程化工作,无需用户掌握复杂编程技能[superscript:3]。但很多用户被“部署难、配置复杂”的问题劝退,事实上,阿里云已针对2026年OpenClaw最新版本,推出计算巢一键部署方案,将复杂流程高度封装,零基础小白10分钟即可完成部署;同时本地搭建流程也已简化,支持Windows、macOS、Linux全系统,无需专业技术储备。
440 13
|
7月前
|
人工智能 算法 开发者
2025年高教社杯E题——AI 辅助智能体测全国大学生数学建模(思路、代码、论文)
2025年高教社杯E题——AI 辅助智能体测全国大学生数学建模(思路、代码、论文)
620 1
|
8月前
|
JSON API 数据格式
借助电商 API,多平台客户评价一键抓取
在电商竞争激烈的环境下,客户评价对消费者决策至关重要。本文介绍如何利用电商平台 API(如 Amazon、eBay、淘宝等)一键抓取多平台客户评价,提升数据收集效率,支持情感分析与市场趋势预测。通过 Python 示例代码,讲解 API 请求构建、多平台整合及数据处理方法,助力商家实现数据驱动的产品优化与市场响应。
233 0
|
10月前
|
人工智能 自然语言处理 IDE
通义灵码你问我答:看看 5 月上线了哪些新功能?
通义灵码5月升级了智能问答(Ask)模式至Agentic模式,支持自主调用工程感知和网络检索工具,使开发者互动更贴合工程场景。新增行间会话(Inline Chat)与行间建议预测(NES)功能,大幅提升代码修改效率。同时发布AI IDE——Lingma IDE,全面集成智能编码能力,开箱即用,无需额外插件。此外,还优化了上下文文件添加体验及其他多项功能,进一步提升开发效率和用户体验。
|
人工智能 编解码 自然语言处理
Aria-UI:港大联合 Rhymes AI 开源面向 GUI 智能交互的多模态模型,整合动作历史信息实现更加准确的定位
Aria-UI 是香港大学与 Rhymes AI 联合开发的多模态模型,专为 GUI 智能交互设计,支持高分辨率图像处理,适用于自动化测试、用户交互辅助等场景。
626 11
Aria-UI:港大联合 Rhymes AI 开源面向 GUI 智能交互的多模态模型,整合动作历史信息实现更加准确的定位
下一篇
开通oss服务