首页 > 编程语言 >并发编程 - 模式与应用

并发编程 - 模式与应用

时间:2023-08-07 23:13:08浏览次数:39  
标签:编程 lock Object 模式 并发 while 线程 sleep response

限制

1、限制对 CPU 的使用

单核 CPU 下,while (true) 里如果什么都不干, CPU 会空转占用会很快达到 100% 。这时 while(true) 里哪怕用 sleep(1) 也会大幅降低 cpu 占用

sleep 实现

while(true) {
 try {
   Thread.sleep(50);
 } catch (InterruptedException e) {
   e.printStackTrace();
 }
}
  • 可以用 wait 或 条件变量达到类似的效果
  • 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景
  • sleep 适用于无需锁同步的场景

 

两阶段终止模式(Two phase termination)

在一个线程 T1 中如何优雅的终止线程 T2,这里的优雅是指给 T2 一个料理后事的机会

1、错误思路

  • 使用线程对象的 stop() 方法停止线程
    • stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
  • 使用 System.exit(int) 方法停止线程
    • 目的仅是停止一个线程,但这种做法会让整个程序都停止

2、两阶段终止

通常有监控线程,每隔几秒(sleep())进行一次系统状态记录,会一直让它 while(true) 运行。但是必须有可以让它停止下来的方法

  • 情况1:如果在 sleep 时被打断了,那么就会有 InterruptException 异常,执行 catch(InterruptException e) 里的内容,这时打断标志位为 false,所以要重新打断一次,让它的标志位变为 true,这样下一次 while 循环,就会判断标志位然后继续走下面料理后事退出循环
  • 情况2:如果在正常执行时(如记录监控日志时)被打断了,那么打断标志位为 true,这样下一次 while 循环,就会判断标志位然后继续走下面的料理后事退出循环

 

 

 

同步模式之保护性暂停

1. 定义

即 Guarded Suspension,用在一个线程等待另一个线程的执行结果

要点:

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

2.实现

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;     }   }    public void complete(Object response) {     synchronized (lock) {       // 条件满足,通知等待线程,返回响应       this.response = response;       lock.notifyAll();     }   }    
}

3.应用

public static void main(String[] args) {
     // 两线程使用同一个 guardedObject
   GuardedObject guardedObject = new GuardedObject();
   new Thread(() -> {
    try {
      // 子线程执行下载
      List<String> response = download();
      log.debug("download complete...");
      guardedObject.complete(response);
    } catch (IOException e) {
      e.printStackTrace();
    }
   }).start();
   log.debug("waiting...");
   // 主线程阻塞等待
   Object response = guardedObject.get();
   log.debug("get response: [{}] lines", ((List<String>) response).size());
}

执行结果

08:42:18.568 [main] c.TestGuardedObject - waiting...
08:42:23.312 [Thread-0] c.TestGuardedObject - download complete...
08:42:23.312 [main] c.TestGuardedObject - get response: [3] lines

4.优点

相比 join ,notify 完了还可以干点别的事

5.带超时版 GuardedObject

控制超时时间

class GuardedObjectV2 {
   private Object response;
   private final Object lock = new Object();    public Object get(long millis) {     synchronized (lock) {       // 1) 记录最初时间       long begin = System.currentTimeMillis();       // 2) 已经经历的时间       long timePassed = 0;       while (response == null) {         // 4) 假设 millis 是 1000,结果在 400 时唤醒了,那么还有 600 要等         long waitTime = millis - timePassed;         log.debug("waitTime: {}", waitTime);         if (waitTime <= 0) {           log.debug("break...");           break;         }         try {           lock.wait(waitTime);         } catch (InterruptedException e) {           e.printStackTrace();         }         // 3) 如果提前被唤醒,这时已经经历的时间假设为 400         timePassed = System.currentTimeMillis() - begin;         log.debug("timePassed: {}, object is null {}",           timePassed, response == null);         }         return response;       }    }
    public void complete(Object response) {       synchronized (lock) {         // 条件满足,通知等待线程         this.response = response;         log.debug("notify...");         lock.notifyAll();       }      } }

 

标签:编程,lock,Object,模式,并发,while,线程,sleep,response
From: https://www.cnblogs.com/suBlog/p/17489441.html

相关文章

  • 并发中atomic BUG分享
    在使用Java做性能测试的过程中,遇到过很多自己抗自己的坎儿。在经历过风风雨雨之后,自认为已经是个并发编程的老司机,没想到前两天又丢进了同一个坑中。保持操作的原子性!!!保持操作的原子性!!!保持操作的原子性!!!重要的事情写三遍。事情是这样,要写一个脚本,需求是对所有的用户进行初始化(......
  • 《Java编程思想第四版》学习笔记06
    为什么要把一个方法声明成final呢?正如上一章指出的那样,它能防止其他人覆盖那个方法。但也许更重要的一点是,它可有效地“关闭”动态绑定,或者告诉编译器不需要进行动态绑定。这样一来,编译器就可为final方法调用生成效率更高的代码。               ......
  • RunnerGo配置场景时接口模式该怎么选
    在进行性能测试时,测试场景的正确配置非常关键。首先,需要根据业务场景和需求,设计出合理的测试场景,再利用相应的工具进行配置,实现自动化的性能测试。在JMeter中,用户需要自己组织测试场景,或是在同一文件中维护多个测试场景,而且每个测试场景必须单独设置各种元素,并且执行测试场景也需要......
  • 编程范式 --- 函数式编程
    定义函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambdacalculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。--百度百科简单说,"函数式编程"是一种"编程范式"(programmingparadigm),也就是如何编写程序的方法论。它属于"结......
  • Python Socket编程
    Socket客户端##py_client.py#py_learn##CreatedbyZ.Steveon2023/8/716:36.#importsocketdeftest_client():#1.创建socketsocket_client=socket.socket()#2.连接到服务器socket_client.connect(("localhost",8091))......
  • Java后端06(代理模式)
    代理模式​ spring中就使用了代理模式,Java中的代理模式分为一下两种静态代理:最简单,但是每次修改都需要重新编译动态代理:分为两种(jdk动态代理--通过接口实现来进行代理&cglib动态代理--通过子类继承来实现代理)静态代理​ 静态代理致命问题:代理对象必须提前编译好,所有代......
  • Element UI 在非template/render 模式下使用ICON要注意的问题
    有很多时候,我们不需要编译Vue和ElementUI,只是想简单的试用一下,做一个原型出来。我们会使用HTML方式编写,这种方式下,使用ICON需要注意一些问题。1.例如CopyDocument图标,如果是用htmltag方式调用,根据vue的组件规范,驼峰格式需要改写成小写横线分割的格式<copy-document></copy-docu......
  • Java设计模式的七大基本原则
    设计模式是为了让程序(软件)具有更好的代码重用性,可读性,可扩展性,可靠性,使程序呈现高内聚,低耦合的特性设计模式的原则其实就收是程序员在编写时,应当遵守的原则,也是各种模式的基础(Java设计模式的七大基本原则)一、单一职责原则<A>对类来说的,即一个类应只负责一项职责,如果A负责......
  • Redis从入门到放弃(9):集群模式
    前面文章我们介绍了Redis的主从模式是一种在Redis中实现高可用性的方式,但也存在一些缺点。1、主从模式缺点写入单点故障:在主从模式中,写入操作只能在主节点进行,如果主节点宕机,写入将无法执行。虽然可以通过升级从节点为主节点来解决,但这会增加故障切换的复杂性。写入压力分......
  • 【Java设计模式004】建造者模式
    大家好,个人gzh是大猪和小猪的小家,我们的gzh是朝阳三只大明白,满满全是干货,分享近期的学习知识以及个人总结(包括读研和IT),跪求一波关注,希望和大家一起努力、进步!!概述首先来看一个例子,假设我们需要建造一个房子,那么必须建造墙、屋顶、地板、门…如果还需要游泳池、健身室,那么该怎么办呢......