在上篇 并发编程Bug起源:可见性、有序性和原子性问题,介绍了操作系统为了提示运行速度,做了各种优化,同时也带来数据的并发问题,
在单线程系统中,代码按照顺序从上往下
顺序执行,执行不会出现问题。比如一下代码:
int a = 1;
int b = 2;
int c = a + b;
程序从上往下执行,最终c
的结果一定会是3
。
但是在多线程环境中,代码就不一定会顺序执行了。代码的运行结果也有不确定性。在开发中,自己本地没问题,一行行查看代码也没有问题,但是在高并发的生产环境就会出现违背常理的问题。
多线程系统提升性能有如下几个优化:
cpu
改成多核的cpu
,每个cpu
都有自己的缓存。cpu
线程切换。这些优化会导致可见性
、原子性
以及有序性
问题,为了解决上述问题,Java
内存模型应运而生。
Java
内存模型是定义了Java
程序在多线程环境中,访问共享内存和内存同步的规范,规定了线程之间的交互方式,以及线程与主内存、工作内存的的数据交换。
导致可见性的原因的是缓存,导致有序性的问题是编译优化,那解决可见性、有序性问题就是禁用缓存和编译优化。这样虽然解决了并发问题,但是性能却下降了。
合理的方案就是按需求禁用缓存和编译优化,在需要的地方添加对应的编码即可。Java内存模型规范了JVM如何按需禁用缓存和编译优化,具体包括volatile
、synchronized
、final
这几个关键字,以及Happens-Before
规则。
在多核cpu
操作系统中每次cpu
都有自己的缓存,cpu
先从内存获取数据,再进行运算。比如下图中线程A和线程B,分别运行自己的cpu
,然后从内存获取变量到自己的cpu
缓存中,并进行计算。
线程B改变了变量之后,线程A是无法获取到最新的值。以下代码中,启动两个线程,线程启动完线程A,循环获取变量,如果是true
,一直执行循环,直到被改成false
才跳出循环,然后再延迟1s
启动线程B,线程修改变量值为true
:
private static boolean flag = true;
// 线程A一直读取变量flag,直到变量为false,才跳出循环
class ThreadA extends Thread {
@Override
public void run() {
while (flag) {
// flag 为 true,一直读取flag字段,flag 为 false 时跳出来。
//System.out.println("一直在读------" + flag);
}
System.out.println("thread - 1 跳出来了");
}
}
// 1s 后线程B将变量改成 false
class ThreadB extends Thread {
@Override
public void run() {
System.out.println("thread-2 run");
flag = false;
System.out.println("flag 改成 false");
}
}
@Test
public void test2() throws InterruptedException {
new Thread1().start();
// 暂停一秒,保证线程1 启动并运行
Thread.sleep(1000);
new Thread2().start();
}
运行结果:
thread-2 run
flag 改成 false
线程A一直处于运行中,说明线程B修改后的变量,线程A并未知道。
将flag
变量添加volatile
声明,修改成:
private static volatile boolean flag = true;
再运行程序,运行结果:
thread-2 run
flag 改成 false
thread - 1 跳出来了
线程B运行完后,线程A也跳出了循环。说明修改了变量后,其他线程也能获取最新的值。
一个未声明
volatile
的变量,都是从各自的cpu
缓存获取数据,线程更新数据之后,其他线程无法获取最新的值。而使用volatile
声明的变量,表明禁用缓存,更新数据直接更新到内存中,每次获取数据都是直接内存获取最新的数据。线程之间的数据都是相互可见的。
可见性来自happens-before
规则,happens-before
用来描述两个操作的内存可见性,如操作Ahappens-before
操作B,那么A的结果对于B是可见的,前面的一个操作结果对后续操作是可见的。happens-before
定义了以下几个规则:
happens-before
同一把锁的加锁操作。happens-before
同一字段的读操作。happens-before
该线程的第一个操作。happens-before
B,且Bhappens-before
C,那么Ahappens-before
C。happens-before
具有传递性。先看一个反常识的例子:
int a=0, b=0;
public void method1() {
b = 1;
int r2 = a;
}
public void method2() {
a = 2;
int r1 = b;
}
定义了两个共享变量a
和b
,以及两个方法。第一个方法将共享变量b
赋值为1
,然后将局部变量r2
赋值为a
。第二个方法将共享变量a
赋值为2
,然后将局部变量r1
赋值为b
。
在单线程环境下,我们可以先调用第一个方法method1
,再调用method2
方法,最终得到r1
、r2
的值分别为1,0
。也可以先调用method2
,最后得到r1
、r2
的值分别为0,2
。
如果代码没有依赖关系,JVM
编译优化可以对他们随意的重排序
,比如method1
方法没有依赖关系,进行重排序:
int a=0, b=0;
public void method1() {
int r2 = a;
b = 1;
}
public void method2() {
int r1 = b;
a = 2;
}
此时在多线程环境下,两个线程交替运行method1
和method2
方法:
重排序后r1
、r2
分别是0
,0
。
那如何解决重排序的问题呢?答案就是将变量声明为volatile
,比如a
或者b
变量声明volatile
。比如b
声明为volatile
,此时b
的赋值操作要happens-before
r1
的赋值操作。
int a=0;
volatile int b=0;
public void method1() {
int r2 = a;
b = 1;
}
public void method2() {
int r1 = b;
a = 2;
}
同一个线程顺序也满足happens-before
关系以及传递性,可以得到r2
的赋值happens-before
a
的赋值。也就表明对a
赋值时,r2
已经完成赋值了。也就不可能出现r1
、r2
为0
、0
的结果。
Java
内存模型是通过内存屏障
来实现禁用缓存
和和禁用重排序
。
内存屏障会禁用缓存,在内存写操作时,强制刷新写缓存,将数据同步到内存中,数据的读取直从内存中读取。
内存屏障会限制重排序操作,当一个变量声明volatile
,它就插入了一个内存屏障,volatile
字段之前的代码只能在之前进行重排序,它之后的代码只能在之后进行重排序。
Java
内存模型(Java Memory Model,JMM)定义了Java
程序中多线程之间共享变量的访问规则,以及线程之间的交互行为。它规定了线程如何与主内存和工作内存交互,以确保多线程程序的可见性、有序性和一致性。
可见性:使用volatile
声明变量,数据读取直接从内存中读取,更新也是强制刷新缓存,并同步到主内存中。
有序性:使用volatile
声明变量,确保编译优化不会重排序该字段。
Happens-Before: 前面一个操作的结果对后续操作是可见的,
Java内存模型
Java内存模型:看Java如何解决可见性和有序性问题
Ubuntuinstallationsudoaptinstalltesseract-ocr pipinstallpytesseract #JetsonNano #sudovim~/.bashrc #exportOPENBLAS_CORETYPE=ARMV8复制Pythontestimportcv2 importpytesseract importnumpyasnp defocr_tesseract(path): img=cv2.imread(path) gray=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) gray,img_bin=cv2.threshold(gray,128,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU) gray=cv2.bitwise_not(img_bin) kernel=np.ones((2,1),np.uint8) img=cv2.erode(gray,kernel,iterations=1) img=cv2.dilate(img,kernel,iterations=1) returnpytesse
2020,我们一起度过了极不寻常的一年,但好在无论多少变动正在发生,还有些东西始终不变。正是这些不变,让我们相信着前方总是美好,让我们发现温暖依然在身边。腾讯人每天都上的乐问,记录下了这些珍贵的“不变”。乐问记录了鹅厂人的生活趣事,沉淀了无数条产品建议,让几万人有了一个跨部门、跨层级沟通的桥梁。在乐问,你能看到最真实最包容的腾讯文化。倒带2020,让我们来看看这一年,腾讯人在乐问上最有温度的18句话,以及这些金句背后那个接地气、有底蕴的腾讯。乐问有温度、有温情,这里有公司对员工的关怀,有员工之间的关爱,留下了真挚的告白,记录着生活的感人点滴。“爱你在心口难开”,但在乐问,却有最多的鹅厂情话。年初,疫情像一记闷拳,猛地砸向我们。尤其是滞留湖北数月的同学,焦虑和担忧是前三个月的主题。但重回正轨时,这一幕让所有的忧虑变成了鼻头一酸、心中一暖——行政同学接武汉小伙伴返深。记录下了这个瞬间的同学,那一刻表示:“想嫁!”疫情初期,形势并不明朗。2月3日,公司早早通知推迟返工时间,让鹅厂er放下心来。2月3日,公司决定推迟返工时间 “员工是最宝贵的财富”,是腾讯通过实际行动对员工说出的情话。2020
原文链接:http://tecdat.cn/?p=5658使用R检测相关主题的社区创建主题网络对于ProjectMosaic,我正在通过分析抽象文本和共同作者社交网络来研究UNCC在社会科学和计算机和信息学方面的出版物。我遇到的一个问题是:如何衡量主题之间的关系(相关性)?特别是,我想创建一个连接类似主题的网络可视化,并帮助用户更轻松地浏览大量主题(在本例中为100个主题)。数据准备我们的第一步是加载作为LDA输出的主题矩阵。LDA有两个输出:字主题矩阵和文档主题矩阵。作为加载平面文件的替代方法,您可以使用topicmodels包lda函数的输出来创建任何单词主题和文档主题矩阵。#读取作者主题矩阵 author.topic<-read.csv("./author_topics.csv",stringsAsFactors=F) # top.words<-word.topics[order(-word.topic[,i])] name$topic_name[i]<-paste(top.words[1:5],collapse="+"
在刷leetcode时,看到前面快的solution加上了如下代码:staticint__=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return0; }();复制自己加上后,发现速度提升不少,百度查了一下,上面避免了两个因素。std::ios::sync_with_stdio(false);iostream默认是与stdio关联在一起的,以使两者同步,因此消耗了iostream不少性能。C++中的std::cin和std::cout为了兼容C,保证在代码中同时出现std::cin和scanf或std::cout和printf时输出不发生混乱,所以C++用一个流缓冲区来同步C的标准流。通过std::ios_base::sync_with_stdio函数设置为false后可以解除这种同步,让std::cin和std::cout不再经过缓冲区,iostream的性能就会提高了很多倍。因此,当解除同步之后,注意不要与scanf和printf混用以免出现问题。[1]std::cin.tie(nullptr);std::cin默认是
大家在面试中,经常会被问到的问题:请简要说明PHP的打印方式都有哪些?或者直接点问:请说明echo、print、print_r的区别看着很简单,一般会出现在初中级的笔试题中。但是要真正说明白这些语言结构或者函数也不是那么简单的事情。今天我们就来好好看看这些打印输出相关的内容。echo最基础的输出语句,不是函数是语言结构,不需要括号。可以使用参数列表,用逗号分隔。但如果加了括号就不能用逗号分隔着输出了。没有返回值。echo'fullstackpm';//正常输出:fullstackpm echo'fullstackpm','is','Good!';//正常输出:fullstackpmisGood! echo('fullstackpm');//正常输出:fullstackpm echo('fullstackpm','is','Good!');//报错了 复制print基本和echo一样,但是不支持参数列表,有返回值。返回值永远是1。
你有没有遇到过:前端代码刚写完,后端的接口又变了。接口文档永远都是不对的。测试工作永远只能临近上线才能开始。为什么前后端分离了,你比从前更痛苦?前后端分离早已经不是新闻,当真正分离之后确遇到了更多问题。要想解决现在的痛,就要知道痛的原因:为什么接口会频繁变动?设计之初没有想好。 这需要提高需求的理解能力和接口设计能力。变动的成本较低。德国有句谚语:“朝汤里吐口水。”只有这样,才能让人们放弃那碗汤,停止不合理的行为。前后端同学坐在一起工作的时候效率会有提升,当后端同学接口变化时,只需要口头上通知一下即可,我们没有文档,我们很敏捷啊。没错,我们需要承认这样配合开发的效率会很高,但是频繁的变动会导致不断返工,造成了另一种浪费,这种浪费是可以被减少,甚至是被消除的。为什么接口文档永远都是不对的?接口文档在定接口时起到一定作用,写完接口就没有用了。后面接口的频繁变化,文档必定会永远落后于实际接口,维护文档的带来了一定的成本却没能带来价值。除非对外提供的接口,否则文档谁来看呢?没人看,用处又在哪?有些公司干脆丢掉接口文档,说我们要拥抱敏捷。所以接口文档落后的原因在于没有给我们带来价值。为什么测试工
计算机本身是不认识程序中给的变量名,不管我们以何种方式给变量命名,最终都会转化为相应的地址,编译器会生成一些符号常量并且与对应的地址相关联,以达到访问变量的目的。 变量是在内存中用来存储数据以供程序使用,变量主要有两个部分构成:变量名、变量类型,其中变量名对应了一块具体的内存地址,而变量类型则表明该如何翻译内存中存储的二级制数。我们知道不同的类型翻译为二进制的值不同,比如整型是直接通过数学转化、浮点数是采用IEEE的方法、字符则根据ASCII码转化,同样变量类型决定了变量所占的内存大小,以及如何在二进制和变量所表达的真正意义之间转化。而指针变量也是一个变量,在内存中也占空间,不过比较特殊的是它存储的是其他变量的地址。在32位的机器中,每个进程能访问4GB的内存地址空间,所以程序中的地址采用32位二进制数表示,也就是一个整型变量的长度,地址值一般没有负数所以准确的说指针变量的类型应该是unsignedint即每个指针变量占4个字节。还记得在定义结构体中可以使用该结构体的指针作为成员,但是不能使用该结构的实例作为成员吗?这是因为编译器需要根据各个成员变量的大小分配相关的内存,用该结构体的
RESTfulConsoleApplicationIntroductionInspiritedbyRESTFularchitecture,AconsoleapplicationtargetedtosamegoalswoulduseamatchofRESTfuldefinitions.DesignForconvenience,wenametheimaginaryconsoleapplicationas'app'.RESTfulWebServiceobjectsAuthentication Requestheader:Authentication Value:"Basic"or":"PropertyDescriptionusernameTheusernameintheBasicAuthenticationpasswordTheusernameintheBasicAuthenticationForauthenticationmethodsOAuthandOAuth,wewillconsiderthenlater.Headers He
声明:本教程,仅作为配置的记录,细节不展开,需要您有一点linux的命令基础,仅作为配置参考。1.系统环境系统:Linux:CentOS7.264位由于CentOS已经内置了OpenSSH,如果您的系统没有,请自行安装。查看ssh版本$ssh-V #输出以下表示没问题,可以继续。版本可能不一致,能用即可。 OpenSSH_6.6.1p1,OpenSSL1.0.1e-fips11Feb2013复制避免系统环境和其他的不一致,请核对您系统的版本,其他发行版请对应修改。 2.安装git建议以下操作都切换到root#请确保您切换到了root账户 $suroot $yuminstall-ygit #验证是否安装成功 $git--version #输出如下内容表示成功: gitversionx.x.x.x复制3.添加git的管理的账户和设置密码设置专门管理git的账号非必须,但是建议这么操作。#添加git账户 $addusergit #修改git的密码 $passwdgit #然后两次输入git的密码确认后。 #查看git是否安装成功 $cd/home&&ls-al #如果
英国《金融时报》网络版今天撰文指出,无人驾驶技术近年来获得了突飞猛进的发展,但人类依旧是横亘在无人驾驶汽车前进道路上的主要障碍,并列出了五个原因。以下为文章全文:先进的技术总能将“神奇”化为“腐朽”。对一代人而言很神奇的创意,在下一代人看来却相当常见。美国创业公司nuTonomy开发的无人驾驶汽车这一现象可以应用于发电、太空飞行和互联网等技术。如今,无人驾驶汽车再次证明这种说法是有道理的。无人驾驶技术取得快速发展过去几周,无人驾驶汽车领域动作不断:新加坡开始对无人驾驶出租车进行公开测试,这在全世界尚属首例;Uber和沃尔沃宣布将于几周内在匹兹堡测试无人驾驶出租车车队;福特表示,将在2021年以前打造出第一辆适用于大众市场的无人驾驶汽车。对于这种技术的支持者来说,无人驾驶汽车无法在短时间内上路。传统汽车低效、危险且污染严重。它们在95%的时间都处于闲置状态,还造成城市街道和停车场拥堵。一旦投入使用,传统汽车又容易发生碰撞,全世界每天平均有3500人死于车祸。90%的车祸是由人为失误引起的。传统汽车还会污染环境,占到燃油总量的45%。因此,全自动汽车和电动汽车的大范围普及,对人类而言绝对是
【新智元导读】英特尔神经网络处理器NMP终于确定将在2017年年底面世,现在传出与Facebook合作的传言。《财富》报道称,Facebook为芯片设计提供了一些思路,但是双方还没有正式的合作关系。英特尔®Nervana™神经网络处理器负责人NaveenRao在官网上撰文,解读了即将于年底推出的新芯片的四大技术特征:新的内存架构旨在最大限度地提高硅计算的利用率;实现AI模型可扩展性的新水平;高度数值并行性:Flexpoint和在2020年要将深度学习训练性能提升100倍的性能表现。英特尔已经准备好在2017年年底推出人工智能芯片。英特尔CEOBrianKrzanich昨天说,Facebook在英特尔新芯片的发布上提供了帮助。Krzanich写道:“当我们将新一代AI硬件推向市场时,我们很高兴Facebook能够提供密切合作并共享其技术见解。英特尔发言人写信给《财富》杂志的一封电子邮件上说,两家公司正在合作,但他们没有确立正式的合作伙伴关系。英特尔Nervana神经网络处理器的来自英特尔在2016年收购的芯片初创公司NervanaSystems。该收购旨在帮助英特尔创建自主的半导体技术,
CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址;在8086PC中,内存地址由段地址和偏移地址组成。8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址。moval,[0] mov已知的功能:1将数据直接送入寄存器2将一个寄存器中的内容送入另一个寄存器中。3将一个内存单元中的内容送入一个寄存器。8086CPU不支持将数据直接放入段寄存器DS中。将数据从寄存器写入内存单元:movbx,1000Hmovds,bx 将段地址设置为ds中的地址mov[0],cx cx中的16位数据送到1000:0处movax,[0] 1000:0处的字型数据送入axmov寄存器,段寄存器也是可以的...将一组长度为N(N<=64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段简单的实例:简单的程序分析:1字在内存中存储时,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。2用mov指令要访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在ds寄存器中。3【
大家好,又见面了,我是你们的朋友全栈君。 COCO数据集格式COCO的全称是CommonObjectsinCOntext,是微软团队提供的一个可以用来进行图像识别的数据集,用于进行物体检测、分割、关键点检测、添加字幕等。 JSON文件的基本格式,以实例分割为例,主要有五个部分:info、licenses、images、annotations、categories{ "info":info, "licenses":[license], "images":[image], "annotations":[annotation], "categories":[category] }复制1.info是关于数据集的一些基本信息"info":{ "description":"Thisisstable1.0versionofthe2014MSCOCOdataset.", "url":"http:\/\/msco
本文旨在对比Elasticsearch和MongoDB高可用和分片的实现机制。 Elasticsearch ES天生就是分布式的,那她又是如何做到天生分布式的? 通过ES官方指南我们可以知道: 一个运行中的Elasticsearch实例称为一个节点,而集群是由一个或者多个拥有相同cluster.name配置的节点组成,它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。 当一个节点被选举成为主节点时,它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。任何节点都可以成为主节点。我们的示例集群就只有一个节点,所以它同时也成为了主节点。 作为用户,我们可以将请求发送到集群中的任何节点,包括主节点。每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回給客户端。E
hasattr(object,name) 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True,否则返回False。 classtest(): name="xiaohua" defrun(self): return"HelloWord" >>>t=test() >>>hasattr(t,"name")#判断对象有name属性 True >>>hasattr(t,"run")#判断对象有run方法 True 复制 getattr(object,name[,default]) 获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,可以在后面添加一对括号。 getattr(obj,name[,default])其中obj为对象名,name是对象中的属性,必须为字符串 >>>classtest(): ...name="xiaohua" ...defrun(s
一:P4588[TJOI2018]数学计算 题意略。 做法: 分块。分成\(sqrt(m)\)个块,算出每个块的乘积,操作一直接乘,操作二找出其对应块,将其数值改为一在做一遍乘积,时间复杂度根号\(m\)。 code: #include<bits/stdc++.h> #definelllonglong usingnamespacestd; constintN=1e5+8; intq,mod; intbl[N]; llkq[1007]; inta[N]; intmain() { intT; cin>>T; while(T--) { cin>>q>>mod; intsiz=sqrt(q); intnq=ceil((double)q/siz); for(inti=1;i<=nq;i++) for(intj=(i-1)*siz+1;j<=min(q,i*siz);j++) bl[j]=i; intop,x; llans=1; for(inti=1;i<=q;i++) { sc
1,故障现象 程序长期运行后,出现"SystemError.Code:8.存储不足,无法处理此命令"错误。 此时检查磁盘空间是足够的。但打不开任务管理器。cmd命令行窗口都打不开。 关闭出错程序后,也无法重启。必须重启操作系统才能恢复正常。 2,错误分析 https://stackoverflow.com/questions/507853/system-error-code-8-not-enough-storage-is-available-to-process-this-command 上文显示,“Delphiappsareleakingatoms,leavingtheidofyourappwithoutdroppingitofffrommemory”,Delphi7使用了RWMAtom进行消息通信,但系统无法自动释放,当16K的空间被分配完后,就会弹出该错误。 采用ATOMTableMonitor程序观察发现,RWMATom的消耗每天约增加20
Java中的javax.servlet.http.Cookie类用于创建一个Cookie Cookie类的主要方法 No. 方法 类型 描述 1 Cookie(String name, String value) 构造方法 实例化Cookie对象,传入cooke名称和cookie的值 2 public String getName() 普通方法 取得Cookie的名字 3 public String getValue() 普通方法 取得Cookie的值 4 public void setValue(String newValue) 普通方法 设置Cookie的值 5 public void setMaxAge(int expiry) 普通方法 设置Cookie的最大保存时间,即cookie的有效期,当服务器给浏览器回送一个cooki
1.1 常见的移动端问题 1.1.1 什么是Retina显示屏,带来了什么问题 retina:一种具备超高像素密度的液晶屏,同样大小的屏幕上显示的像素点由1个变为多个,如在同样带下的屏幕上,苹果设备的retina显示屏中,像素点1个变为4个 在高清显示屏中的位图被放大,图片会变得模糊,因此移动端的视觉稿通常会设计为传统PC的2倍。 那么,前端的应对方案是: 设计稿切出来的图片长宽保证为偶数,并使用backgroud-size把图片缩小为原来的1/2 //例如图片宽高为:200px*200px,那么写法如下 .css{width:100px;height:100px;background-size:100px100px;} 其它元素的取值为原来的1/2,例如视觉稿40px的字体,使用样式的写法为20px .css{font-size:20px} 1.1.2 百度禁止转码 通过百度手机打开网页时,百度可能会对你的网页进行转码,往你页面贴上它的广告,非常之恶心。不过我们可以通过这个meta