关于线程的缓存刷新

今天又是摸鱼的一天,在群里闲聊的时候突然有位群友题了个问题:

群友们反应很快,一下子就解决了没有加关键字volatile,不能保证可见性。所以循环线程中的kaiguan变量一直读取的是线程缓存中的值,而线程缓存的值一直无法读取到主内存中的值。

当然这个问题难不倒这位提问的群友,所以他又提问了。

除了加volatile之外,还有没有其他方式?

正好闲着无聊,我便开始试着解决这个问题。

public class test2 {

    private static boolean kaiguan =true;
    private static void go(){
        new Thread(()->{
            while (kaiguan){
            }

            System.out.println("事情做完了");
        }).start();
        new Thread(()->{
            try {
                Thread.sleep(1000*3);
                kaiguan=false;
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }).start();
    }

    public static void main(String[] args) {
        go();
    }


}

首先我问了ChatGPT

如果不使用 volatile 关键字,也可以使用其他的多线程机制来保证可见性,例如使用 AtomicBoolean 类,这个类提供了 get()set() 方法,可以保证操作的原子性和可见性。
修改后的代码如下所示:
private static AtomicBoolean kaiguan = new AtomicBoolean(true);
private static void go() {
new Thread(() -> {
while (kaiguan.get()) {
Thread.yield(); // 或者使用Thread.sleep(),暂停线程一段时间
}
System.out.println("事情做完了");
}).start();
new Thread(() -> {
try {
Thread.sleep(1000 * 3);
kaiguan.set(false); // 设置kaiguan变量为false,退出循环
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
public static void main(String[] args) {
go();
}
在上述代码中,我们使用了 AtomicBoolean 类来代替原来的 boolean 类型的 kaiguan 变量,并在 while 循环中使用了 kaiguan.get() 方法来获取 kaiguan 变量的值,从而保证可见性。在另一个线程中,我们使用 kaiguan.set(false) 方法将 kaiguan 变量设置为 false ,从而退出循环。

可以看到 除了使用volatile 来声明变量,我们还可以用AtomicBoolean 来声明kaiguan。同样能保证可见性。

那如果不用AtomicBoolean声明kaiguan呢?

我看到了下面这篇文章:

线程的缓存何时刷新? - 简书 (jianshu.com)

在Doug Lea大神的Concurrent Programming in Java一书中有这样一个片段来描述synchronized这个关键字:

In essence, releasing a lock forces a flush of all writes from working memory employed by the thread, and acquiring a lock forces a (re)load of the values of accessible fields. While lock actions provide exclusion only for the operations performed within a synchronized method or block, these memory effects are defined to cover all fields used by the thread performing the action.

简单翻译一下:从本质上来说,当线程释放一个锁时会强制性的将工作内存中之前所有的写操作都刷新到主内存中去,而获取一个锁则会强制性的加载可访问到的值到线程工作内存中来。虽然锁操作只对同步方法和同步代码块这一块起到作用,但是影响的却是线程执行操作所使用的所有字段。

也就是说我们可以用加锁来解决线程刷新这个问题。

所以我们可以手动加上System.out.println();来退出该循环。

因为System.out.println();底层是加锁的

    public void println() {
        newLine();
    }
    
        private void newLine() {
        try {
            synchronized (this) {
                ensureOpen();
                textOut.newLine();
                textOut.flushBuffer();
                charOut.flushBuffer();
                if (autoFlush)
                    out.flush();
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }
    

我们在看看chatgpt的回答,既然里面有提到yield()与sleep(),那么我们就试试

Thread.yield();
与
Thread.sleep(0);

发现果然成功跳出循环,那么yield()与sleep(0)到底发生了什么导致缓存刷新呢?

没错就是上下文切换!

yield()与sleep(0)会导致上下文切换,从而导致缓存失效,从而拉去主内存中的新值。

当然我们也可以直接使用Unsafe方法中的loadFence()方法。

使用UnsafeFactory.getUnsafe().loadFence();也同样可以跳出循环,因为loadFence: 可以保证在这个屏障之前的所有读操作都已经完成。

Unsafe需要我们通过反射获取,直接调用会报错:

  public static Unsafe getUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

在寻找其他答案的过程中我还发现final关键字同样也有刷新缓存的作用

首先自定义一个类,将其中的num设置为final


public  class TestTempOne {
  final int num; //设为final;
    TestTempOne(int num){
        this.num=num;
    }

}

private static void go(){
        new Thread(()->{
            while (kaiguan){
//                new TestTempOne(0);  //跳出循环
//               new String("a");      //跳出循环
//                new Integer(0);      //死循环
//                new Integer(129); //死循环
                new Integer(100000000); //死循环
            }

可以看到最终会跳出循环,但是有个问题Integer中value的值同样也是final。但却不能刷新缓存。而String则是一个final char数组,也可以跳出循环。目前没有找到答案,如果有大佬知道答案,请告知我一下!

总结:我目前知道的有六种:

1、使用volatile

2、使用synchronized或者Lock

3、使用AtomicBoolean

4、使用UnsafeFactory.getUnsafe().loadFence();

5、使用yield()与sleep()

6、final关键字

本文转载于网络 如有侵权请联系删除

相关文章

  • Ansible自动化配置详解

    第1章Ansible基本概述1.1ansible是一个配置管理系统configurationmanagementsystem,你只需要可以使用ssh访问你的服务器或设备就行。1.安装软件 2.配置服务1.2ansible能做什么ansible可以帮助我们完成一些批量任务,或者完成一些需要经常重复的工作。  比如:同时在100台服务器上安装nfs服务,并在安装后启动服务。  比如:将某个文件一次性拷贝到100台服务器上。  比如:每当有新服务器加入工作环境时,你都要为新服务器部署某个服务,也就是说你需要经常重复的完成相同的工作。  这些场景中我们都可以使用到ansible。1.3ansible软件特点1.ansible不需要单独安装客户端,SSH相当于ansible客户端。 2.ansible不需要启动任何服务,仅需安装对应工具即可。 3.ansible依赖大量的Python模块来实现批量管理。 4.ansible配置文件/etc/ansible/ansible.cfg 实现从管理机m01到其他机器的密钥认证第2章Ansible安装配置2.1ansible借助公钥批量管理创建及利用非交换

  • 10. 系统分析垃圾收集器

    一、垃圾收集算法垃圾收集常用的算法有三种。标记-清除算法,标记-复制算法,标记-整理算法。下面一个一个来看:1.1标记清除算法标记清除算法分为“标记”和“清除”两个阶段:标记存活的对象,统一回收所有未被标记的对象(一般选择这种);也可以反过来,标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。1.1.1标记清除算法的原理当堆中的有效内存空间(availablememory)被耗尽的时候,就会停止整个程序(也被称为stoptheworld),然后进行两项工作,第一项则是标记,第二项则是清除。标记:Collector从引用根结点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。 清除:Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。 1.1.2标记清除算法存在的问题标记清除算法是最基础的收集算法,比较简单,但是会带来两个明显的问题:1.效率问题如果需要标记的对象太多,效率不高如果内存空间太大,效率也不高2.空间问题标记清除后会产生大量不连续的碎片1.2标记复制算法标记复制算法包含两个

  • 全网首发!你没玩过的pygame小游戏开发「马赛逻辑」

    大家好,我是云朵君!Python除了不能帮你生孩子,还真无所不能!今天给大家带来一个很有意思的python小游戏开发,文末提供源码,一起学习呀~作者简介:Seon塞翁,数据分析从业者,专注用python处理数据、调教excel、开发有趣实用的GUI小玩意儿,乐于分享python学习之路上的经验技巧。本号长期接受优质文章投稿,详情请移步至公号菜单栏【云朵之家】-【投稿】,稿酬丰厚,欢迎来稿!?点击关注|设为星标|干货速递?游戏简介马赛逻辑,是一个类似数独和扫雷的逻辑小游戏,根据棋盘周围的数据提示点亮方格,因外形像马赛克而得名。在手机游戏中有多款APP可以体验该游戏,如Peak、Nonogram、Crossme等。但在PC端,笔者暂时还未发现复刻版,于是打算自己动手实现一番。手游app马赛逻辑的基本玩法如下图所示,上侧横向的各组数字为:对每一列中存在的目标方格的标注,如2表示该列有2个连续的目标,12表示该列有1个独立的目标+2个连续的目标。左侧纵向的各组数据为对每一行的标注。通过上、左两侧的提示,将所有目标方格点亮即为通关。马赛逻辑的基本玩法核心代码解析在正式开始游戏开发之前,我们可以先

  • DAPP开发类型介绍

    DAPP开发类型介绍首先,在文章的开头,让我们用几句话简单总结一下。DAPP的正式名称被翻译为分布式应用程序。它可以理解为一个建立在各种区块链上的APP。DAPP所有者区块链的所有固有优势,如权力下放和不可篡改。目前主流的DAPP都是ETH和EOS链下的产品。随着区块链3.0时代的到来,更多的厂商开始探索应用落地问题。理论如何应用于实践?区块链有哪些玩法?DAPP可能是他们从理论走向实践的重要一步。FOMO3D之后,在大量的人获利之后,金融DAPP开始出现在人们的眼中。在圈子里,一切都需要知道。跟不上市场发展的步伐,最终的损失也是自己的。今天简单介绍一下市场上主流的DAPP类型。第一种:游戏类在币圈,如果说到底是什么吸引了用户。我觉得其他的都是空的。只有当你得到了实实在在的利益,你才会真正投入其中。根据dappworld的说法,像dapp这样的游戏是当前的主流。其中,分为传统游戏和与金融彩票相结合的交易游戏。类似的加密猫和其他传统的dapp游戏我们都知道更多,不做更多。像fomo3d和lastwinner这样的游戏,最近才出现,虽风险比较多,但他们也是高利润的。所以近期模仿游戏像竹笋一

  • 潮涌智造,后发的U9cloud能否挑战金蝶云星空霸主地位?

    文|曾响铃来源|科技向令说(xiangling0815)在企业管理软件行业,国内软件管理厂商正在加速崛起。2020年初,在新冠疫情的刺激下,我国制造业的数字化转型迎来更加高速的增长期,也极大地推动了国产软件管理品牌的发展。 大众所熟知的钉钉、企业微信、飞书等软件只是冰山一角。真正的企业管理软件行业基本全面涉及经营生产流程,如人力资源(HR)、企业资源计划(ERP)、产品生命周期管理(PLM)、制造执行管理系统(MES)等模块,其中正在以用友、金蝶等国产明星品牌为焦点构建起新的竞争格局。1制造业数字革命全面加速,企业管理软件成为“香饽饽”当前,制造业全面转向数字化升级,已成大势。在全球范围来说,越来越多的国家或地区把制造业数字化作为推动传统产业转型升级的重要途径,积极推动新一代信息技术与制造业深度融合,大力发展先进制造、服务型制造和智能制造。与此同时,我国制造业的低成本比较优势日趋减弱,若要进一步提高产业发展质量,重塑制造业竞争优势,就必须加快发展数字化制造,加紧推动制造业的数字化转型。为此,十四五规划全面聚焦产业数字化转型,推动“上云用数赋智”行动,重点对制造业的设计研发、生产制造、仓

  • 优衣库 UNIQLO,藏着多少秘密

    最近在优衣库买衣服,发现收银员不像往常一样用扫码设备来扫描标签上的二维码,而是把衣服的标签往一个方形的黑座上一放,然后信息就录入电脑了。还真是第一次见到这种操作。跟收银员确认,确实是在这个小标签里藏着些秘密: 虽然以前知道有RFID标签这种东西,可还真是第一次知道他还能做在纸质的标签里。回到家很好奇的对它研究了一番。先用灯透射一下!黑色的像两个牛角一样的东西就是金属天线了。它可以收集读卡器发出的射频信号的能量,并供给RFID芯片。同时它也是跟读卡器通信的天线。我们用水把标签溶解开,可以更清晰的看一下:上图中中间黑色的像个米粒儿似的就是RFID芯片了。下面对RFID做一简单的介绍:RFID(RadioFrequencyIdentification)射频识别芯片,相关标准主要有:ISO11784/ISO11785(低频),ISO14223(低频),ISO/IEC14443标准(13.56MHz),ISO/IEC15693标准(13.56MHz),ISO/IEC18000标准(各部分针对不同频率-2135KHz以下,-313.56MHz,-42.45GHz,-6860-960MHz,-743

  • 科普 | 论垃圾分类与边缘计算的关系

    小明是一位普通市民。 每天,小明和邻居们一样,将生活垃圾混在一起,扔到小区的垃圾箱。然后,环卫人员进行收集运送,送到垃圾中转站。最后,再从垃圾中转站运到垃圾填埋场或焚烧厂,进行掩埋、焚烧。也有部分垃圾,会进行分拣处理再利用。为了保护环境,提高垃圾的价值,政府开始推行垃圾分类政策。政府要求,每家每户必须进行垃圾分类,然后投放到不同的垃圾桶。环卫人员将分类后的垃圾,运送到垃圾中转站。接收垃圾后,垃圾中转站可以更方便地进行分拣处理,送到垃圾填埋场、焚烧厂以及回收厂。不同的垃圾处理厂,可以直接接收属于自己的垃圾,然后直接进行垃圾处理。以上这个简单的例子,是一个标准的“垃圾分类处理流程”。其实,这更是一个非常经典的边缘计算案例。垃圾分类之前,对垃圾的分拣工作,是垃圾中转站负责进行处理的。我们可以把它理解为传统的“云”。居民的家,我们可以称之为“端”。 环卫工人的运输,可以称之为“管”。而填埋场、焚烧厂和回收厂,我们可以理解为不同的应用。这种传统方式的问题在于,经过混合运输之后的垃圾,分拣难度更大。垃圾分类之后,相当于分拣这个计算行为,从“云”(垃圾中转站)下沉到“端”(居民家)。算力下沉最完美的

  • 《最佳实践》-NIO知识梳理

    1、概述NIO(Non-blockingI/O,在Java领域,也称为NewI/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。核心组件主要包括:ChannelBufferSelectorJavaNIO:ChannelsandBuffers(通道和缓冲区)标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。JavaNIO:AsynchronousIO(异步IO)JavaNIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。JavaNIO:Selectors(选择器)JavaNIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。2、基础组件2.1、ChannelChannel与Stream的区别你可以

  • leetcode:83 删除排序链表中的重复元素

    电脑网络不行啊。。。。 题目这么垃圾就不用解释了把。 因为有序,所以相邻./** *Definitionforsingly-linkedlist. *functionListNode(val){ *this.val=val; *this.next=null; *} */ /** *@param{ListNode}head *@return{ListNode} */ vardeleteDuplicates=function(head){ letp=head; while(p&&p.next) { if(p.val===p.next.val) { p.next=p.next.next; } else{ p=p.next; } } returnhead; };复制开始遍历链表的开始。letp=head;复制当前节点的值等于下一个的值就删除下一个节点的元素.if(p.val===p.next.val) { p.next=p.next.next; }复制问题? 如果next没有值的话,会报错的。 因为要相等啊,比较啊,有值才能比较是吧。 那为什么p.next=p.next.n

  • 百世快递财报:净亏损大幅缩窄38%,来之不易

    配图来自Canva8月12日,“百世集团正寻求在香港二次上市”的消息,在业内炸开了锅。网络消息透露:百世集团此次上市计划主要是旗下快递和快运业务,不包括百世供应链、百世云等业务。且计划尚处于初步阶段,其发行规模和目标估值尚未确定,而百世已聘请瑞士信贷和摩根大通牵头上市进程,百世集团的大股东阿里巴巴集团也认可此举。对此消息,百世集团仅平淡回复“不予置评”。上市消息确认碰壁的人们,将目光转向百世集团最新财报,试图从财报中寻找百世集团需要二次上市的蛛丝马迹。8月18日早间,百世集团公布2020年第二季度业绩。财报显示,百世集团第二季度营收84.18亿元,较去年同期的87.88亿元下降4.2%。但净亏损3089.9万元,去年同期亏损2237.1万元,相比收窄38%。摊薄每股亏损0.06元,去年同期每股亏损0.05元。虽然亏损依旧,但亏损大幅缩窄,与盈利的“距离”无限拉近,已是百世集团所尽的最大努力。净亏损大幅缩窄,来之不易要知道,市场上关于百世的争议可不少,而“上市三年至今,仍未走出亏损状态”、“四通一达里,唯一亏损的成员”,一直是百世快递备受诟病的原因。事实也是如此,连年亏损已成百世快递常态

  • [案例] 快速对接德尔福/Delphi EDI

    本次知行软件为汽车电缆行业某客户提供EDI的技术服务,是同时和三位国外贸易合作伙伴进行EDI对接,在双方的共同努力下,最终成功对接了Nexans,KSD,Delphi三位贸易合作伙伴。在对接三位贸易合作伙伴时,EDI需求基本都一致:需要接收来自贸易合作伙伴的需求预测,按照需求预测完成生产后,向贸易合作伙伴交货,交货完成后,发送发票给贸易合作伙伴,完成款项的结算。不过也不是完全相同的,例如报文标准存在不同,Delphi使用的报文标准是EDIFACT,而KSD和NEXANS使用的报文标准是VDA标准,这种标准经常用于德国汽车行业。在进行本次EDI项目实施的时候,我们按照客户要求,将项目以紧急程度分出了优先级,先进行的是Delphi项目的实施,然后进行KSD和Nexans项目的实施。本文中,我们以Delphi的需求为主,详细聊一聊项目的需求和实施过程中遇到的问题。项目需求DelphiEDI项目是Delphi发起的需求。事实上,目前大多数国内客户都是在国外贸易合作伙伴的要求下,才开始接触EDI的。原因主要是因为EDI技术在国外已经发展的较为成熟了,但在国内还属于新兴技术。说回正题,Delphi

  • python3操作Excel (一)

    #第一篇: ##openpyxl模块使用:安装: pipinstallopenpyxlexcel表中有图像,需要安装pillow库。 pipinstallPillow代码:fromopenpyxlimportWorkbook wb=Workbook() #grabtheactiveworksheet ws=wb.active #Datacanbeassigneddirectlytocells ws['A1']=42 #Rowscanalsobeappended ws.append([1,2,3]) #Pythontypeswillautomaticallybeconverted importdatetime ws['A2']=datetime.datetime.now() #Savethefile wb.save("sample.xlsx")复制openpyxl模块使用:创建一个工作簿:fromopenpyxlimportWorkbook wb=Workbook()复制工作簿最少有一个工作表: openpyxl.wo

  • kubelet statusManager 源码分析

    本篇文章没有接上篇继续更新kube-controller-manager,kube-controller-manager的源码阅读笔记也会继续更新,笔者会同时阅读多个组件的源码,阅读笔记也会按组件进行交叉更新,交叉更新的目的一是为了加深印象避免阅读完后又很快忘记,二是某些代码的功能难以理解,避免死磕,但整体目标是将每个组件的核心代码阅读完。在前面的文章中已经介绍过kubelet的架构以及启动流程,本章会继续介绍kubelet中的核心功能,kubelet中包含数十个manager以及对CNI、CRI、CSI的调用。每个manager的功能各不相同,manager之间也会有依赖关系,本文会介绍比较简单的statusManager。statusManager源码分析kubernetes版本:v1.16 statusManager的主要功能是将pod状态信息同步到apiserver,statusManage并不会主动监控pod的状态,而是提供接口供其他manager进行调用。statusManager的初始化kubelet在启动流程时会在NewMainKubelet方法中初始化其核心组件,包括

  • ElasticSearch(7.2.2)-索引的介绍和使用

    版权声明:本文为博主原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/weixin_42528266/article/details/102796160简介:手把手进行索引的操作 新增请求curl-XPUT"localhost:9200/nba"复制响应{ "acknowledged":true, "shards_acknowledged":true, "index":"nba" }复制获取/查询请求curl-XGET"localhost:9200/nba"复制响应{ "nba":{ "aliases":{}, "mappings":{}, "settings":{ "index":{ "creation_date":"1563078

  • node.js的http模块实例演示

    上世纪六七十年代,红岸基地一直在向茫茫外太空发送讯号,当叶文洁通过太阳作为广播,将地球的讯号向外发送时,宇宙的各个先进文明都接收到了讯号,其中就包括了离我们最近的三体星。本篇用node.js的http模块模拟这一事件。lethttp=require('http') //创建一个web服务器 letserver=http.createServer() server.on('request',function(){ console.log('我们接收到了一个用原始膜发送讯号的文明,这个文明竟然完全不知道宇宙的黑暗森林法则,我们暂不清理她,观察下这个文明的状态') }) letport=8000 server.listen(port,function(){ console.log('在浏览器访问:http://127.0.0.1:'+port+',你将把你的请求发送到宇宙中...') })复制开启服务:☁01[master]⚡node08.js 在浏览器访问:http://127.0.0.

  • DeepMind 推出分布式训练框架 IMPALA,开启智能体训练新时代

    AI研习社按,日前,DeepMind推出一种全新的分布式智能体训练框架IMPALA,该框架具有高度可扩展性,将学习和执行过程分开,使用了一种名为V-trace的离策略(off-policy)修正算法,具有显著的加速性能,极高的效率。具体如何呢,AI研习社将其原文编译整理如下:深度强化学习(DeepRL)在一系列任务中取得很显著的成果,比如机器人的连续控制问题、玩围棋和Atari等游戏。目前为止,我们看到的这些成果仅限于单一任务,每个任务都要单独对智能体进行调参和训练。在我们最近的工作中,研究了在多个任务中训练单个智能体。今天我们发布DMLab-30,这是一组横跨很多挑战的新任务,在视觉统一的环境中,有着普通的行动空间(actionspace)。想训练好一个在许多任务上都有良好表现的智能体,需要大量的吞吐量,有效利用每个数据点。为此,我们开发了一种全新的、高度可扩展的分布式智能体训练框架IMPALA(重点加权行动-学习器框架,ImportancesWeightedActor-LearnerArchitectures),这种框架使用了一种名为V-trace的离策略(off-policy)修

  • Java 数据类型转换

    本文节选自《NetkillerJava手札》 作者:netkiller 1.5.类型1.5.1.String1.5.1.1.随机字符串 publicStringrandomString(Stringchars,intlength){ Randomrand=newRandom(); StringBuilderbuf=newStringBuilder(); for(inti=0;i<length;i++){ buf.append(chars.charAt(rand.nextInt(chars.length()))); } returnbuf.toString(); } 复制1.5.1.2.字符串替换处理 publicclassTest{ publicTest(){ //TODOAuto-generatedconstructorstub } publicstaticvoidmain(String[]args){ //TODOAuto-generatedmethodstub System.out.println("201

  • 深度解析中国机器人产业链(多图)

    导读:随着中国人口红利消失,机器人不仅在制造业上正在替代工人,还将在军事、服务、娱乐等领域取代人类,“钢铁侠”已不仅仅存在于美国科幻电影中,而正走入我们的生活。近两年,中国机器人产业投资如火如荼,几十家上市公司宣布进入机器人领域,而与此同时,机器人关键技术和核心零部件尚未突破,研发人员奇缺,低端机器人产能重复建设。目前国内机器人产能是否过剩?中国机器人企业应该采取怎样的战略?中国在哪些应用领域有望实现进口替代?未来工业机器人、服务机器人、军用机器人的空间有多大?(不清戳大)then一、工业机器人工业机器人产业链由零部件企业、本体企业、代理商、系统集成商、最终用户构成。通常,本体企业设计本体、编写软件,采购通过代理商销售给系统集成商,系统集成商直接面向终端客户。有的本体企业和代理商也会兼做系统集成商。本体是机器人产业链的核心。目前,国内的机器人企业多为系统集成商。根据国际经验来看,国内的机器人产业发展更接近于美国模式,即以系统集成商为主,单元产品外购或贴牌,为客户提供交钥匙工程。与单元产品的供应商相比,系统集成商还要具有产品设计能力、项目经验,并在对用户行业深刻理解的基础之上,提供可适应

  • C++运算符重载(三)之递增运算符重载

    递增运算符重载作用:通过重载递增运算符,实现自己的整型数据重载前置递增运算符classMyInteger{ friendostream&operator<<(ostream&out,MyIntegermyint); public: MyInteger(){ m_Num=0; } //前置++ MyInteger&operator++(){//注意& //先++ m_Num++; //再返回 return*this; } private: intm_Num; }; //左移运算符重载 ostream&operator<<(ostream&out,MyIntegermyint){//加上&就是引用传递。 out<<myint.m_Num; returnout; } //前置++先++再返回 voidtest01(){ MyIntegermyInt; cout<<++myInt<<endl;//先++,后输出 cout&

  • ? limma | 配对样本的差异分析怎么搞!?(一)

    1写在前面最近在用limma包做配对样本的差异分析,在这里和大家分享一下吧。大家可以先思考一下,配对和非配对的结果一样吗???应用场景:同一病人的癌和癌旁样本,同一样品的多时间点测序等。2用到的包rm(list=ls()) library(tidyverse) library(limma) library(GEOquery) 复制3示例数据这里我从GEO数据库上download了一个dataset。? 在3个样本中对T细胞和B细胞分别进行了转录组分析。 每个样本的细胞都分为Control或anti-BTLA组。我们先常规下载数据吧,boxplot不是很齐啊,强迫症的我必须标准化!?GSE194314<-getGEO('GSE194314',destdir=".",getGPL=F) exprSet<-exprs(GSE194314[[1]]) boxplot(log2(exprSet)) 复制4获取分组数据pdata<-pData(GSE194314[[1]]) 复制5整理分组数据这里我们提取出分组数据后转为factor。ind

  • Canal:同步mysql增量数据工具,一篇详解核心知识点

    老刘是一名即将找工作的研二学生,写博客一方面是总结大数据开发的知识点,一方面是希望能够帮助伙伴让自学从此不求人。由于老刘是自学大数据开发,博客中肯定会存在一些不足,还希望大家能够批评指正,让我们一起进步! 背景 大数据领域数据源有业务库的数据,也有移动端埋点数据、服务器端产生的日志数据。我们在对数据进行采集时根据下游对数据的要求不同,我们可以使用不同的采集工具来进行。今天老刘给大家讲的是同步mysql增量数据的工具Canal,本篇文章的大纲如下: Canal的概念mysql中主备复制实现原理Canal如何从MySQL中同步数据Canal的HA机制设计各种数据同步解决方法的简单总结 老刘争取用这一篇文章让大家直接上手Canal这个工具,不再花别的时间来学习。 mysql主备复制实现原理 由于Canal是用来同步mysql中增量数据的,所以老刘先讲mysql的主备复制原理,之后再讲Canal的核心知识点。 根据这张图,老刘把mysql的主备复制原理分解为如下流程: 主服务器首先必须启动二进制日志binlog,用来记录任何修改了数据库数据的事件。主服务器将数据的改变记录到二进制bi

相关推荐

推荐阅读