线程同步模式之保护性暂停

简介: 保护性暂停是一种同步模式,用于保护共享资源的完整性。在多线程或多进程环境中,如果多个线程或进程同时访问共享资源,可能会导致数据不一致或者竞态条件等问题

👳我亲爱的各位大佬们好😘😘😘
♨️本篇文章记录的为 线程同步模式之保护性暂停 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。
♨️如果文章有什么需要改进的地方还请大佬不吝赐教❤️🧡💛
👨‍🔧 个人主页 : 阿千弟

何为保护性暂停

保护性暂停是一种同步模式,用于保护共享资源的完整性。在多线程或多进程环境中,如果多个线程或进程同时访问共享资源,可能会导致数据不一致或者竞态条件等问题。为了避免这种情况,可以使用保护性暂停来保护共享资源。

实现方式:

在访问共享资源之前,先获取一个锁,然后再访问共享资源。如果锁已经被其他线程或进程占用,则当前线程或进程会被阻塞,直到锁被释放为止。在访问完共享资源之后,需要释放锁,以便其他线程或进程可以继续访问共享资源。

作用:

保护性暂停可以保证共享资源的完整性,但是也会带来一定的性能开销。因为每个线程或进程在访问共享资源之前都需要获取锁,如果锁的竞争比较激烈,就会导致线程或进程的等待时间增加,从而影响系统的性能。因此,在使用保护性暂停时,需要权衡保证数据完整性和系统性能之间的关系,选择合适的锁机制和并发控制策略。

  1. 具体定义:

Guarded Suspension(被监视的挂起),用在一个线程等待另一个线程的执行结果
在这里插入图片描述

要点

  • 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject
  • 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)
  • JDK 中,join 的实现、Future 的实现,采用的就是此模式
  • 因为要等待另一方的结果,因此归类到同步模式

代码实现

GuardedObject

@Slf4j
public class GuardedObject {
   
   

    private Object response;
    private final Object lock = new Object();

    //直到收到返回结果会被唤醒, 死等
    public Object get(){
   
   
        synchronized (lock){
   
   
            while (response==null){
   
   
                try {
   
   
                    lock.wait();
                } catch (InterruptedException e) {
   
   
                    e.printStackTrace();
                }
            }
        }
        return response;
    }

    //接受结果的等待时间为mills, 如果该期间仍然没有接受到返回结果, 则
    public Object get(long mills){
   
   
        // 1) 记录最初时间
        long beginTime = System.currentTimeMillis();
        // 2) 已经经历的时间
        long passTime = 0;
        synchronized (lock){
   
   
            while (response==null){
   
   
                // 4) 假设 millis 是 1000,结果在 400 时唤醒了,那么还有 600 要等
                long waitTime = mills - passTime;
                if (waitTime <= 0){
   
   
                    break;
                }
                try {
   
   
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
   
   
                    e.printStackTrace();
                }
                // 3) 如果提前被唤醒,这时已经经历的时间假设为 400
                passTime = System.currentTimeMillis() - beginTime;
                log.debug("timePassed: {}, object is null {}",passTime, response == null);
            }
        return response;
        }
    }

    public void complete(Object response){
   
   
        synchronized (lock){
   
   
            // 条件满足,通知等待线程
            this.response = response;
            lock.notifyAll();
        }
    }

    public static void main(String[] args) {
   
   
        GuardedObject guardedObject = new GuardedObject();

        new Thread(()->{
   
   
            try {
   
   
                List<String> response = Downloader.download();
                log.info("下载完成");
                guardedObject.complete(response);
            } catch (IOException e) {
   
   
                e.printStackTrace();
            }
        }).start();

        log.info("正在下载");

        Object response = guardedObject.get(500);
        if(response!=null){
   
   
            log.debug("get response: [{}] lines", ((List<String>) response).size());
        } else {
   
   
            log.debug("can't get response");
        }

    }
}

下载案例demo

public class Downloader {
   
   
    public static List<String> download() throws IOException {
   
   
        HttpURLConnection conn = (HttpURLConnection) new URL("https://www.baidu.com/").openConnection();
        List<String> lines = new ArrayList<>();
        try (BufferedReader reader =
                     new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
   
   
            String line;
            while ((line = reader.readLine()) != null) {
   
   
                lines.add(line);
            }
        }
        return lines;
    }
}

测试,超时

17:41:21.194 [main] INFO com.jrm.juc.GuardedObject - 正在下载
17:41:21.700 [main] DEBUG com.jrm.juc.GuardedObject - timePassed: 503, object is null true
17:41:21.701 [main] DEBUG com.jrm.juc.GuardedObject - can't get response
17:41:25.560 [Thread-0] INFO com.jrm.juc.GuardedObject - 下载完成

Process finished with exit code 0

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对Java后端或者对spring, 分布式, 云原生感兴趣的朋友,请多多关注💖💖💖
👨‍🔧 个人主页 : 阿千弟

目录
相关文章
|
3月前
|
负载均衡 算法 安全
基于Reactor模式的高性能网络库之线程池组件设计篇
EventLoopThreadPool 是 Reactor 模式中实现“一个主线程 + 多个工作线程”的关键组件,用于高效管理多个 EventLoop 并在多核 CPU 上分担高并发 I/O 压力。通过封装 Thread 类和 EventLoopThread,实现线程创建、管理和事件循环的调度,形成线程池结构。每个 EventLoopThread 管理一个子线程与对应的 EventLoop(subloop),主线程(base loop)通过负载均衡算法将任务派发至各 subloop,从而提升系统性能与并发处理能力。
168 3
|
数据处理
多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)
多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)
118 1
|
4月前
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
125 0
|
8月前
|
SQL 数据建模 BI
【YashanDB 知识库】用 yasldr 配置 Bulkload 模式作单线程迁移 300G 的业务数据到分布式数据库,迁移任务频繁出错
问题描述 详细版本:YashanDB Server Enterprise Edition Release 23.2.4.100 x86_64 6db1237 影响范围: 离线数据迁移场景,影响业务数据入库。 外场将部分 NewCIS 的报表业务放到分布式数据库,验证 SQL 性能水平。 操作系统环境配置: 125G 内存 32C CPU 2T 的 HDD 磁盘 问题出现的步骤/操作: 1、部署崖山分布式数据库 1mm 1cn 3dn 单线启动 yasldr 数据迁移任务,设置 32 线程的 bulk load 模式 2、观察 yasldr.log 是否出现如下错
|
10月前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
NoSQL Redis
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
141 0
|
NoSQL 关系型数据库 MySQL
简述redis的单线程模式
简述redis的单线程模式
163 0
|
Prometheus 监控 数据可视化
通用快照方案问题之Hystrix进行指标监控如何解决
通用快照方案问题之Hystrix进行指标监控如何解决
123 0

热门文章

最新文章