当前位置: 首页 > news >正文

沈阳医疗网站制作外贸出口网

沈阳医疗网站制作,外贸出口网,企业年金查询官网,seo企业网络推广培训👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…
  • 👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家
  • 📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术
  • 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
  • 🍂博主正在努力完成2023计划中:源码溯源,一探究竟
  • 📝联系方式:nhs19990716,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬👀

文章目录

  • 前言
  • 问题描述
  • 解决思路
    • 常规解法
      • 问题
    • 其他解法
  • 总结

前言

学完了并发编程,是否真的能够灵活应用其思想呢?

实践才是检验真理的唯一标准,好记性不如烂笔头。

下面就让我以我一个朋友社招面试钉钉的一道面试题来讲解下并发编程的实际应用吧。

问题描述

// 假设我们有如下代码,query 是公共方法会提供给任意业务方调用,请完成 query 方法
// 要求:多线程情况下 loadFromServer 调用次数最多只执行一次,且每次调用query方法要有回调回来的数据
public class Main {private Executor mExecutor = Executors.newFixedThreadPool(4);private Executor mServerExecutor = Executors.newFixedThreadPool(4);private Data mData;public void queryData(Callback callback) {if (callback == null) {return;}mExecutor.execute(new Runnable() {@Overridepublic void run() {// todo 代码写在这}});}private void loadFromServer(Callback callback) {mServerExecutor.execute(new Runnable() {@Overridepublic void run() {// mocktry {Thread.sleep(5000L);} catch (InterruptedException e) {throw new RuntimeException(e);}if (callback != null) {callback.onSuccess(new Data());}}});}public static class Data {}public interface Callback {void onSuccess(Data data);}
}

测试类

public class Test {private static volatile int cnt = 0;public static void main(String[] args) throws InterruptedException {Main main = new Main();for (int i = 0 ; i < 5; i++) {new Thread(() -> {main.queryData(new Main.Callback() {@Overridepublic void onSuccess(Main.Data data) {if (data == null) {System.out.println("data is null");} else {System.out.println("getData is " + data);}++cnt;}});}).start();}Thread.sleep(20000L);System.out.println("cnt = " + cnt);}}

这道题的本质就是说,多线程情况下 loadFromServer 调用次数最多只执行一次,且每次调用query方法要有回调回来的数据,光从题意上我们能够很清楚的想到思路,这并不难。

解决思路

常规解法

首先能想到的是,这一看不就是很像多线程情况下的单例模式?其能保证多线程情况下 loadFromServer 调用次数最多只执行一次,但是还需要每次调用query方法要有回调回来的数据,也就是说,假如一次来了五个调用,那么其他调用要等loadFromServer 调用过一次之后,才能够返回,这不就是典型的线程同步问题,可以使用CountDownLatch来实现。

基于此分析,那么我们针对这个问题就非常清晰了,这也是立马能想到的解法之一了。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;// 假设我们有如下代码,query 是公共方法会提供给任意业务方调用,请完成 query 方法
// 要求:多线程情况下 loadFromServer 调用次数最多只执行一次,且每次调用query方法要有回调回来的数据
public class Main {private Executor mExecutor = Executors.newFixedThreadPool(4);private Executor mServerExecutor = Executors.newFixedThreadPool(4);private Data mData;// 定义一个 volatile 变量来保证线程可见性和禁止指令重排序private volatile boolean mHasLoadFromServer = false;private CountDownLatch mLatch = new CountDownLatch(1);public void queryData(Callback callback) {if (callback == null) {return;}mExecutor.execute(new Runnable() {@Overridepublic void run() {// 双重检查加锁if (!mHasLoadFromServer) {synchronized (Main.this) {if (!mHasLoadFromServer) {loadFromServer(new Callback() {@Overridepublic void onSuccess(Data data) {mData = data;mLatch.countDown();}});mHasLoadFromServer = true;try {mLatch.await(); // 等待 loadFromServer 执行完成} catch (InterruptedException e) {e.printStackTrace();}}}}callback.onSuccess(mData);}});}private void loadFromServer(Callback callback) {mServerExecutor.execute(new Runnable() {@Overridepublic void run() {// mocktry {Thread.sleep(5000L);} catch (InterruptedException e) {throw new RuntimeException(e);}mData = new Data();if (callback != null) {callback.onSuccess(mData);}}});}public static class Data {}public interface Callback {void onSuccess(Data data);}
}

运行结果:

getData is Main$Data@17f2e0c9
getData is Main$Data@17f2e0c9
getData is Main$Data@17f2e0c9
getData is Main$Data@17f2e0c9
getData is Main$Data@17f2e0c9
cnt = 5

问题

我们重点看一下这块的代码

public void queryData(Callback callback) {if (callback == null) {return;}mExecutor.execute(new Runnable() {@Overridepublic void run() {// 双重检查加锁if (!mHasLoadFromServer) {synchronized (Main.this) {if (!mHasLoadFromServer) {loadFromServer(new Callback() {@Overridepublic void onSuccess(Data data) {mData = data;mLatch.countDown();}});mHasLoadFromServer = true;try {mLatch.await(); // 等待 loadFromServer 执行完成} catch (InterruptedException e) {e.printStackTrace();}}}}callback.onSuccess(mData);}});}

我们每次其实都需要进行一个锁的判断,假如说后续,如果后续mData不为null,其实是可以直接调用返回的,并不需要进行判断和锁的竞争,这也是性能并不好的情况。

修改:

public void queryData(Callback callback) {if (callback == null) {return;}if (mData != null) {callback.onSuccess(mData);return;}mExecutor.execute(new Runnable() {@Overridepublic void run() {// 双重检查加锁if (!mHasLoadFromServer) {synchronized (Main.this) {if (!mHasLoadFromServer) {loadFromServer(new Callback() {@Overridepublic void onSuccess(Data data) {mData = data;mLatch.countDown();}});mHasLoadFromServer = true;try {mLatch.await(); // 等待 loadFromServer 执行完成} catch (InterruptedException e) {e.printStackTrace();}}}}callback.onSuccess(mData);}});}

但是该方法可能还存在问题,假如在等待的过程中,积攒了太多太多的请求,那么我们集成进行回调的时候,可能超过我们服务器所能承受的阈值,那么可能会影响影响,为此可以采用其他解法来实现。

其他解法

public class Main {private Executor mExecutor = Executors.newFixedThreadPool(4);private Executor mServerExecutor = Executors.newFixedThreadPool(4);private Data mData;private volatile boolean mIsLoading = false;private List<Callback> mCallbacks = new ArrayList<>();public void queryData(Callback callback) {if (callback == null) {return;}if (mData != null) {callback.onSuccess(mData);return;}synchronized (this) {if (mIsLoading) {// 数据正在加载中,等待回调// 将回调函数添加到数据加载完成后的回调列表中mCallbacks.add(callback);return;}mIsLoading = true;mCallbacks.add(callback);}mExecutor.execute(new Runnable() {@Overridepublic void run() {if (mData == null) {loadFromServer(new Callback() {@Overridepublic void onSuccess(Data data) {System.out.println("loadFromServer");mData = data;notifyCallbacks(data);}});} else {// 数据已经加载完成,直接返回callback.onSuccess(mData);}}});}private void loadFromServer(Callback callback) {mServerExecutor.execute(new Runnable() {@Overridepublic void run() {// mocktry {Thread.sleep(5000L);} catch (InterruptedException e) {throw new RuntimeException(e);}if (callback != null) {callback.onSuccess(new Data());}}});}private void notifyCallbacks(Data data) {synchronized (this) {for (Callback callback : mCallbacks) {callback.onSuccess(data);}mCallbacks.clear();}}public static class Data {}public interface Callback {void onSuccess(Data data);}
}

这种解法是采用一种回调集合的方法,假如说等待回调的请求过多,完全可以采用生产者消费者的思想来实现,基于回调集合,等到将来回调的时候,根据实际的一个性能阈值从回调集合中进行回调,使得系统能够稳定的运行。

总结

其实这个问题不仅仅想说一些解法的小细节,还是想说,其实这个面试题,更像是真实业务模型中抽取出来的,很偏向于业务开发,当我们学习完并发编程的时候,能够学习这样真实的业务模型,并能针对不同的场景进行分析,就能够触类旁通,更好的将并发编程的解决思路应用于实际问题的解决中去。

http://www.15wanjia.com/news/188698.html

相关文章:

  • 呼和浩特制作网站做网站服务器价格多少合适
  • 上海专业网站制作设计公司哪家好可做生物试卷的网站
  • 做一款什么网站赚钱自己做视频网站 在优酷推广
  • 网站开发 软件网站制作模板图片
  • 深圳网站页面设计公司深圳高端婚介公司
  • 消费返利系统网站建设电商模板网站
  • 中山网站建设解决方案佛山网络发言人平台
  • 国外网站怎么进入怎么修改wordpress 后台登陆密码
  • 简单手机网站模板企业网站在百度搜索不到
  • 长沙百度网站建设凡科轻站
  • 深圳做英文网站的公司wordpress pagination
  • 一个空间可以做几个网站吗找竞价托管公司
  • 如何找到网站管理员宁波平面设计公司
  • 刷赞网站推广qq免费企业网站备案号密码忘记
  • 合肥网站关键词推广成都百度网站优化
  • 在哪找可以做网站的江苏网站关键词优化优化
  • 高校信息公开网站建设上海网络推广培训机构
  • 各网站收录重庆建设厅网站
  • 凌河网站建设推广扬州市工程建设招标网
  • 医疗网站优化徐州网站开发多少钱
  • 系统模板html四川seo多少钱
  • 自学摄影教程的网站有哪些查询网域名查询
  • 网站建设支付宝小说wordpress主题
  • 辽宁网站优化免费下载微信2023
  • 洛阳做网站公司汉狮价格人际网络营销能做吗
  • 自建团体电子商务网站建设成本wordpress 定宽
  • 建设通网站登录不进去网站做301排名会掉
  • 自己做网站要会什么软件网络设计网站建设类网站模板
  • 做淘宝客网站服务器wordpress shortcode 插件
  • 网站开发环境实验报告wordpress远程上传媒体文件