首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

C++之类的继承关系学习总结(一)

一、类的组合关系: 1、整体与部分的关系 组合关系,从字面上来理解的话,就是谁也离不开谁,必须相互组合在一起才行,例如我们生活当中的电脑组成: 代码示例: #include<iostream>#include<string>usingnamespacestd;classMemory{public:Memory(){cout<<"Memory()"<<endl;}~Memory(){cout<<"~Memory()"<<endl;}};classDisk{public:Disk(){cout<<"Disk()"<<endl;}~Disk(){cout<<"~Disk()"<<endl;}};classCPU{public:CPU(){cout<<"CPU()"<<endl;}~CPU(){cout<<"~CPU()"<<endl;}};classMainBoard{public:MainBoard(){cout<<"MainBoard()"<<endl;}~MainBoard(){cout<<"~MainBoard()"<<endl;}};class Computer //这个地方不仅描述了事物,也还描述了关系,里面只要有一个类不存在,电脑这个类也就不复存在了。{MemorymMem;DiskmDisk;CPUmCPU;MainBoardmMainBoard;public: Computer()//这里会先调用类成员的构造函数,之后调用电脑类的构造函数,这说明了组合关系;电脑类对象的创建,要依赖上述四个类的对象的创建。{cout<<"Computer()"<<endl;}voidpower(){cout<<"power()"<<endl;}voidreset(){cout<<"reset()"<<endl;}~Computer()//电脑类析构的时候,也会将对应的类成员析构,这说明同生死;说明了电脑类对象的存在完全依赖于类成员对象的存在。{{cout<<"~Computer()"<<endl;}};intmain(){Computerc;return0;} 运行结果: root@txp-virtual-machine:/home/txp#./a.outMemory()Disk()CPU()MainBoard()Computer()~Computer()~MainBoard()~CPU()~Disk()~Memory() 2、组合关系的特点: 将其它类的对象作为当前类的成员使用 当前类的对象与成员对象的生命周期相同 成员对象在用法上与普通对象完全一致 二、类的继承关系: 说到这个继承,你可以把它类比成生活当中的父亲和儿子,儿子继承的父亲的长相特征。那么在我们面向对象中继的承又是指什么呢? 1、面向对象中的继承是指类之间的父子关系 子类拥有父类的所有属性和行为 子类就是一种特殊的父类 子类对象可以当作父类对象使用 子类中可以添加父类中没有的方法和属性 2、继承代码描述形式: classParent{intmv;public:voidmethod(){}};classChild:publicParent//描述继承关系{}; 代码示例: #include<iostream>#include<string>usingnamespacestd;classParent{intmv;public:Parent(){cout<<"Parent()"<<endl;mv=100;}voidmethod(){cout<<"mv="<<mv<<endl;}};classChild:publicParent{public:voidhello(){cout<<"I'mChildcalss!"<<endl;}};intmain(){Childc;c.hello();c.method();return0;} 运行结果: root@txp-virtual-machine:/home/txp#./a.outParent()I'mChildclass!mv=10 3、继承规则: 子类就是一个特殊的父类 子类对象可以直接初始化父类对象 子类对象可以直接赋值给父类对象 说明:继承是c++中代码复用的重要手段。通过继承,可以获得父类的所有功能,并且可以在子类中重写已有的功能,或者添加新功能。 代码示例: #include<iostream>#include<string>usingnamespacestd;classMemory{public:Memory(){cout<<"Memory()"<<endl;}~Memory(){cout<<"~Memory()"<<endl;}};classDisk{public:Disk(){cout<<"Disk()"<<endl;}~Disk(){cout<<"~Disk()"<<endl;}};classCPU{public:CPU(){cout<<"CPU()"<<endl;}~CPU(){cout<<"~CPU()"<<endl;}};classMainBoard{public:MainBoard(){cout<<"MainBoard()"<<endl;}~MainBoard(){cout<<"~MainBoard()"<<endl;}};classComputer{MemorymMem;DiskmDisk;CPUmCPU;MainBoardmMainBoard;public:Computer(){cout<<"Computer()"<<endl;}voidpower(){cout<<"power()"<<endl;}voidreset(){cout<<"reset()"<<endl;}~Computer(){cout<<"~Computer()"<<endl;}};classHPBook:publicComputer{stringmOS;public:HPBook(){mOS="Windows8";}voidinstall(stringos){mOS=os;}voidOS(){cout<<mOS<<endl;}};classMacBook:publicComputer{public:voidOS(){cout<<"MacOS"<<endl;}};intmain(){HPBookhp;hp.power();hp.install("Ubuntu16.04LTS");hp.OS();cout<<endl;MacBookmac;mac.OS();return0;} 运行结果: root@txp-virtual-machine:/home/txp#./a.outMemory()Disk()CPU()MainBoard()Computer()power()Ubuntu16.04LTSMemory()Disk()CPU()MainBoard()Computer()MacOS~Computer()~MainBoard()~CPU()~Disk()~Memory()~Computer()~MainBoard()~CPU()~Disk()~Memory() 4、小结: 继承是面向对象中类之间的一种关系 子类拥有父类的所有属性和行为 子类对象可以当作父类对象使用 子类中可以添加父类没有的方法和属性 继承是面向对象中代码复用的重要手段(换句话说,就是不要去写重复的代码,提高工作效率) 三、总结: 好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。我是txp,下期见! 本文分享自微信公众号 - TXP嵌入式(txp1121518wo-)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

ES[7.6.x]学习笔记(十一)与SpringBoot结合

在前面的章节中,我们把ES的基本功能都给大家介绍完了,从ES的搭建、创建索引、分词器、到数据的查询,大家发现,我们都是通过ES的API去进行调用,那么,我们在项目当中怎么去使用ES呢?这一节,我们就看看ES如何与我们的SpringBoot项目结合。 版本依赖 SpringBoot默认是有ElasticSearch的Starter,但是它依赖的ES客户端的版本比较低,跟不上ES的更新速度,所以我们在SpringBoot项目中要指定ES的最新版本,如下: <properties> <elasticsearch.version>7.6.1</elasticsearch.version> </properties> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency> 我们在项目中指定ES客户端的版本为7.6.1。 配置文件 然后我们在SpringBoot的配置文件application.properties当中,配置ES集群的地址,如下: spring.elasticsearch.rest.uris=http://192.168.73.130:9200,http://192.168.73.131:9200,http://192.168.73.132:9200 多个地址之间我们使用,隔开即可。 与ES交互 所有配置的东西都准备好了,下面我们看看在程序当中如何交互,还记得前面咱们提到的动态映射吗?这个东西是非常的好用的,简化了我们不少的工作量。在这里我们还用前面的索引ik_index举例,我们先看看目前ik_index索引中有哪些字段, 在索引中只有3个字段,id、title和desc。接下来我们在创建索引ik_index对应的实体类,内容也很简单,具体如下: @Setter@Getter public class IkIndex { private Long id; private String title; private String desc; private String category; } 在实体类中,我们新添加了一个字段category表示分类,我们可以联想一下,category字段动态映射到ES当中会是什么类型?对了,就是text类型,我们再深入想一步,text类型会用到全文索引,会用到分词器,而在索引ik_index当中,我们配置了默认的分词器是IK中文分词器。能够想到这里,我觉得你对ES了解的比较深入了。 接下来,我们就要编写service了,并向ik_index索引中添加一条新的数据,如下: @Service public class EService { @Autowired private RestHighLevelClient client; /** * 添加索引数据 * @throws IOException */ public void insertIkIndex() throws IOException { IkIndex ikIndex = new IkIndex(); ikIndex.setId(10l); ikIndex.setTitle("足球"); ikIndex.setDesc("足球是世界第一运动"); ikIndex.setCategory("体育"); IndexRequest request = new IndexRequest("ik_index"); // request.id("1"); request.source(JSON.toJSONString(ikIndex), XContentType.JSON); IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT); System.out.println(indexResponse.status()); System.out.println(indexResponse.toString()); } } 首先,我们要引入ES的高等级的客户端RestHighLevelClient,由于我们在配置文件中配置了ES集群的地址,所以SpringBoot自动为我们创建了RestHighLevelClient的实例,我们直接自动注入就可以了。然后在添加索引数据的方法中,我们先把索引对应的实体创建好,并设置对应的值。 接下来我们就要构建索引的请求了,在IndexRequest的构造函数中,我们指定了索引的名称ik_index,索引的id被我们注释掉了,ES会给我们默认生成id,当然自己指定也可以。大家需要注意的是,这个id和IkIndex类里的id不是一个id,这个id是数据在ES索引里的唯一标识,而IkIndex实体类中的id只是一个数据而已,大家一定要区分开。然后我们使用request.source方法将实体类转化为JSON对象并封装到request当中,最后我们调用client的index方法完成数据的插入。我们看看执行结果吧。 CREATED IndexResponse[index=ik_index,type=_doc,id=f20EVHIBK8kOanEwfXbW,version=1,result=created,seqNo=9,primaryTerm=6,shards={"total":2,"successful":2,"failed":0}] status返回的值是CREATED,说明数据添加成功,而后面的响应信息中,包含了很多具体的信息,像每个分片是否成功都已经返回了。我们再用elasticsearch-head插件查询一下,结果如下: 数据插入成功,并且新添加的字段category也有了对应的值,这是我们期望的结果。下面我们再看看查询怎么使用。代码如下: public void searchIndex() throws IOException { SearchRequest searchRequest = new SearchRequest("ik_index"); SearchSourceBuilder ssb = new SearchSourceBuilder(); QueryBuilder qb = new MatchQueryBuilder("desc","香蕉好吃"); ssb.query(qb); searchRequest.source(ssb); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] hits = response.getHits().getHits(); for (SearchHit hit : hits) { String record = hit.getSourceAsString(); System.out.println(record); } } 我们先创建一个查询请求,并指定索引为ik_index; 然后我们创建一个请求体SearchSourceBuilder,再构建我们的查询请求QueryBuilder,QueryBuilder是一个接口,它的实现类有很多,对应着ES中的不同种类的查询,比如咱们前面介绍的bool和boosting查询,都有对应的实现类。在这里,咱们使用MatchQueryBuilder并查询desc包含香蕉好吃的数据,这个查询咱们在前面通过API的方式也查询过。 最后我们封装好请求,并通过client.search方法进行查询,返回的结构是SearchResponse。 在返回的结果中,我们获取对应的数据,咦?这个为什么调用了两次Hits方法?咱们可以从API的返回值看出端倪,如下: 我们可以看到返回的结果中确实有两个hits,第一个hits中包含了数据的条数,第二个hits中才是我们想要的查询结果,所以在程序中,我们调用了两次hits。 在每一个hit当中,我们调用getSourceAsString方法,获取JSON格式的结果,我们可以用这个字符串通过JSON工具映射为实体。 我们看看程序运行的结果吧, {"id":1,"title":"香蕉","desc":"香蕉真好吃"} {"id":1,"title":"香蕉","desc":"香蕉真好吃"} {"id":1,"title":"橘子","desc":"橘子真好吃"} {"id":1,"title":"桃子","desc":"桃子真好吃"} {"id":1,"title":"苹果","desc":"苹果真好吃"} 查询出了5条数据,和我们的预期是一样的,由于使用IK中文分词器,所以desc中包含好吃的都被查询了出来,而我们新添加的足球数据并没有查询出来,这也是符合预期的。我们再来看看聚合查询怎么用, public void searchAggregation() throws IOException { SearchRequest searchRequest = new SearchRequest("ik_index"); SearchSourceBuilder ssb = new SearchSourceBuilder(); TermsAggregationBuilder category = AggregationBuilders.terms("category").field("category.keyword"); ssb.aggregation(category); searchRequest.source(ssb); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); Terms terms = response.getAggregations().get("category"); for (Terms.Bucket bucket : terms.getBuckets()) { System.out.println(bucket.getKey()); System.out.println(bucket.getDocCount()); } } 同样,我们创建一个SearchRequest,然后再创建一个TermsAggregationBuilder,TermsAggregationBuilder我们指定了name叫做category,这个name对应着上一节中的那个自定义的名称,大家还有印象吗? 后面的field是我们要聚合的字段,注意这里因为category字段是text类型,默认是不能够做聚合查询的,我们指定的是category.keyword,还记得这个keyword类型吗?它是不使用分词器的,我们使用这个keyword类型是可以的。 最后把AggregationBuilder封装到查询请求中,进行查询。 查询后,我们怎么去取这个aggregation呢?取查询结果我们是通过hits,取聚合查询,我们要使用aggregation了,然后再get我们的自定义名称response.getAggregations().get("category")。至于前面的类型,它是和AggregationBuilder对应的,在咱们的例子中使用的是TermsAggregationBuilder,那么我们在取结果时就要用Terms;如果查询时使用的是AvgAggregationBuilder,取结果时就要用Avg。 在取得Terms后,我们可以获取里边的值了。运行一下,看看结果。 体育 1 key是体育,doc_count是1,说明分类体育的数据只有1条。完全符合我们的预期,这个聚合查询的功能非常重要,在电商平台中,商品搜索页通常列出所有的商品类目,并且每个类目后面都有这个商品的数量,这个功能就是基于聚合查询实现的。 好了,到这里,ES已经结合到我们的SpringBoot项目中了,并且最基础的功能也已经实现了,大家放心的使用吧~

优秀的个人博客,低调大师

ES[7.6.x]学习笔记(六)分析器

在前面的章节中,我们给大家介绍了索引中的映射类型,也就是每一个字段都有一个类型,比如:long,text,date等。这和我们的数据库非常的相似,那么它的不同之处是什么呢?对了,就是全文索引,在ES当中,只有text类型的字段才会用的全文索引,那么这里就会引出ES中一个非常重要的概念,文本分析器(Text analysis)。 分析器使ES支持全文索引,搜索的结果是和你搜索的内容相关的,而不是你搜索内容的确切匹配。我们用ES官网中的例子给大家举例,假如你在搜索框中输入的内容是Quick fox jumps,你想得到的结果是A quick brown fox jumps over the lazy dog,或者结果中包含这样的词fast fox或foxes leap。 分析器之所以能够使搜索支持全文索引,都是因为有分词器(tokenization),它可以将一句话、一篇文章切分成不同的词语,每个词语都是独立的。假如你在ES索引中添加了一条记录the quick brown fox jumps,而用户搜索时输入的内容是quick fox,并没有完全匹配的内容,但是因为有了分词器,你索引的内容被切分成了不同的、独立的词,用户搜索的内容也会进行相应的切分,所以用户搜索的内容虽然没有完全匹配,但也能够搜索到想要的内容。 分析器除了要做分词,还要做归一化(Normalization)。分词器能够使搜索内容在每一个词上匹配,但这种匹配也只是在字面上进行的匹配。 比如你搜索Quick,但是不能匹配到quick,它们的大小写不同。 比如你搜索fox,但是不能匹配到foxes,它是复数形式。 比如你搜索jumps,不能匹配到leaps,虽然它们是同义词。 为了解决这些问题,分析器要把这些分词归一化到标准的格式。这样我们在搜索的时候就不用严格的匹配了,相似的词语我们也能够检索出来,上面的3种情况,我们也能够搜索出相应的结果。 分析器的组成 分析器,无论是内置的,还是自定义的,都是由3部分组成:字符过滤器(character filters)、分词器(tokenizers)、分词过滤器(token filters)。 字符过滤器 字符过滤器接收最原始的文档,并且可以改变其内容,比如:可以把中文的一二三四五六七八九,变成阿拉伯数字123456789。它还可以过滤html标签,并对其进行转义。还可以通过正则表达式,把匹配到的内容转化成其他的内容。一个分析器可以有多个字符过滤器,也可以没有字符过滤器。 分词器 一个分析器只能有一个确定的分词器,它可以把一句话分成若干个词,比如:空格分词器。当你输入一句话Quick brown fox!,它将被切分成[Quick, brown, fox!]。 分词过滤器 分词过滤器接收分词并且可以改变分词,比如:小写分词过滤器,它将接收到的分词全部转换成小写。助词过滤器,它将删除掉一些公共的助词,比如英语里的 the,is,are等,中文里的的,得等。同义词过滤器,它将在你的分词中,添加相应的同义词。一个分析器可以有多个分词过滤器,它们将按顺序执行。 我们在建立索引和搜索时,都会用的分析器。 配置文本分析器 前面我们讲了分析器的基本概念,也了解了全文搜索的基本步骤。下面我们看一下如何配置文本分析器,ES默认给我们配置的分析器是标准分析器。如果标准的分析器不适合你,你可以指定其他的分析器,或者自定义一个分析器。 ES有分析器的api,我们指定分析器和文本内容,就可以得到分词的结果。比如: POST _analyze { "analyzer": "whitespace", "text": "The quick brown fox." } 返回的结果如下: { "tokens": [ { "token": "The", "start_offset": 0, "end_offset": 3, "type": "word", "position": 0 }, { "token": "quick", "start_offset": 4, "end_offset": 9, "type": "word", "position": 1 }, { "token": "brown", "start_offset": 10, "end_offset": 15, "type": "word", "position": 2 }, { "token": "fox.", "start_offset": 16, "end_offset": 20, "type": "word", "position": 3 } ] } 我们指定的分析器是空格分析器,输入的文本内容是The quick brown fox.,返回结果是用空格切分的四个词。我们也可以测试分析器的组合,比如: POST _analyze { "tokenizer": "standard", "filter": [ "lowercase", "asciifolding" ], "text": "Is this déja vu?" } 我们指定了标准的分词器,小写过滤器和asciifolding过滤器。输入的内容是Is this déja vu?,我们执行一下,得到如下的结果: { "tokens": [ { "token": "is", "start_offset": 0, "end_offset": 2, "type": "<ALPHANUM>", "position": 0 }, { "token": "this", "start_offset": 3, "end_offset": 7, "type": "<ALPHANUM>", "position": 1 }, { "token": "deja", "start_offset": 8, "end_offset": 12, "type": "<ALPHANUM>", "position": 2 }, { "token": "vu", "start_offset": 13, "end_offset": 15, "type": "<ALPHANUM>", "position": 3 } ] } 我们可以看到结果中,is变成了小写,déja变成了deja,最后的?也过滤掉了。 为指定的字段配置分析器 我们在创建映射时,可以为每一个text类型的字段指定分析器,例如: PUT my_index { "mappings": { "properties": { "title": { "type": "text", "analyzer": "whitespace" } } } } 我们在my_index索引中,创建了title字段,它的类型是text,它的分析器是whitespace空格分析器。 为索引指定默认的分析器 如果我们觉得为每一个字段指定分析器过于麻烦,我们还可以为索引指定一个默认的分词器,如下: PUT my_index { "settings": { "analysis": { "analyzer": { "default": { "type": "whitespace" } } } } } 我们为my_index索引指定了默认的分析器whitespace。这样我们在创建text类型的字段时,就不用为其指定分析器了。 这一节给大家介绍了分析器,我们可以看到例子中都是使用的英文分析器,下一节我们一起看一下强大的中文分析器。

优秀的个人博客,低调大师

ES[7.6.x]学习笔记(四)字段类型(mapping)

在上一节中,我们创建了索引,在创建索引的时候,我们指定了mapping属性,mapping属性中规定索引中有哪些字段,字段的类型是什么。在mapping中,我们可以定义如下内容: 类型为String的字段,将会被全文索引; 其他的字段类型包括:数字、日期和geo(地理坐标); 日期类型的格式; 动态添加字段的映射规则; 字段的可用类型如下: 简单的类型,比如:text,keyword,date,long,double,boolean,ip。我们可以看到,类型当中没有String,字符串的类型是text,所有text类型的字段都会被全文索引。数字类型有两个,long(长整型)和double(浮点型)。 JSON的层级类型:Object(对象)和Nested(数组对象)。Object类型时,该字段可以存储一个JSON对象;Nested类型时,该字段可以存储一个数组对象。 复杂的类型:包括 geo_point、geo_shape和completion。 在索引中创建映射 我们在创建索引的时候可以同时创建映射,就如同上一节的内容。也可以在索引创建好以后,再去创建映射,请求的方式如下: PUT /my-index { "mappings": { "properties": { "age": { "type": "integer" }, "email": { "type": "keyword" }, "name": { "type": "text" } } } } 请求的方法我们要使用PUT,路径是我们的索引名称,请求体当中是我们为索引添加的字段和字段的类型。 在存在的映射中添加字段 正如上面所示,我们在一个索引中添加了字段,但是现在我们要补充额外的字段,这时,我们要怎么做呢? PUT /my-index/_mapping { "properties": { "employee-id": { "type": "keyword", "index": false } } } 我们使用PUT方法,后面跟随我们的索引名称,再接上_mapping,请求体中是我们新添加的映射字段,我们指定了字段的类型为keyword,index索引为false,说明这个字段只用于存储,不会用于搜索,搜索这个字段是搜索不到的。 我们在更新字段时候,是不能修改字段的类型的。如果我们要修改字段的类型,最好是新建一个新的字段,指定正确的类型,然后再更新索引,以后我们只需要查询这个新增的字段就可以了。 查看索引中的字段映射 如果我们要查看已知索引的字段映射,可以向ES发送如下的请求: GET /my-index/_mapping 请求的方法是GET,请求的路径是我们索引的名称my-index,再加上一个_mapping,得到的返回结果如下: { "my-index" : { "mappings" : { "properties" : { "age" : { "type" : "integer" }, "email" : { "type" : "keyword" }, "employee-id" : { "type" : "keyword", "index" : false }, "name" : { "type" : "text" } } } } } 返回的结果中,我们可以看到索引的名称my-index,还有我们添加的字段,也包括后续补充的employee-id字段。 好了,关于索引的字段映射就先给大家介绍到这里。

优秀的个人博客,低调大师

Java队列学习第一篇之列介绍

Java并发之显式锁和隐式锁的区别 在面试的过程中有可能会问到:在Java并发编程中,锁有两种实现:使用隐式锁和使用显示锁分别是什么?两者的区别是什么?所谓的显式锁和隐式锁的区别也就是说说Synchronized(下文简称:sync)和lock(下文就用ReentrantLock来代之lock)的区别。 本文主要内容:将通过七个方面详细介绍sync和lock的区别。通过生活case中的X二代和普通人比较大家更容易理解这两者之间的区别 Java中隐式锁:synchronized;显式锁:lock sync和lock的区别 一:出身不同 从sync和lock的出身(原始的构成)来看看两者的不同。 Sync:Java中的关键字,是由JVM来维护的。是JVM层面的锁。 Lock:是JDK5以后才出现的具体的类。使用lock是调用对应的API。是API层面的锁 sync是底层是通过monitorenter进行加锁(底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于monitor对象的。只有在同步块或者是同步方法中才可以调用wait/notify等方法的。因为只有在同步块或者是同步方法中,JVM才会调用monitory对象的);通过monitorexit来退出锁的。 而lock是通过调用对应的API方法来获取锁和释放锁的。 我们通过Javap命令来查看调用sync和lock的汇编指令: 编辑 从编译后的汇编指令,我们也能够清晰的看出sync关键字和lock的区别。 第一不同一句话概述:可以把sync理解为官二代或者是星二代。从娘胎出来自带光环的。Lock就是我们普通努力上进的人。 二:使用方式不同 Sync是隐式锁。Lock是显示锁 所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁的操作。 我们大家都知道,在使用sync关键字的时候,我们使用者根本不用写其他的代码,然后程序就能够获取锁和释放锁了。那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话话,是不会出现死锁的。 在使用lock的时候,我们使用者需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。手动获取锁方法:lock.lock()。释放锁:unlock方法。需要配合tyr/finaly语句块来完成。 两者用法对比如下: 编辑 用生活中的一个case来形容这个不同:官二代和普通人的你在进入机关大院的时候待遇。官二代不需要出示什么证件就可以进入,但是你需要手动出示证件才可以进入。 三:等待是否可中断 Sync是不可中断的。除非抛出异常或者正常运行完成 Lock可以中断的。中断方式: 1:调用设置超时方法tryLock(long timeout ,timeUnit unit) 2:调用lockInterruptibly()放到代码块中,然后调用interrupt()方法可以中断 生活中小case来理解这一区别:官二代一般不会做饭。都会去餐厅点餐等待着餐厅出餐。普通人的你既可以去餐厅等待,如果等待时间长的话,你就可以回去自己做饭了。 四:加锁的时候是否可以公平 Sync;非公平锁 lock:两者都可以的。默认是非公平锁。在其构造方法的时候可以传入Boolean值。 true:公平锁 false:非公平锁 生活中小case来理解这个区别:官二代一般都不排队,喜欢插队的。普通人的你虽然也喜欢插队。但是如果遇到让排队的情况下,你还是会排队的。 Lock的公平锁和非公平锁: 五:锁绑定多个条件来condition Sync:没有。要么随机唤醒一个线程;要么是唤醒所有等待的线程。 Lock:用来实现分组唤醒需要唤醒的线程,可以精确的唤醒,而不是像sync那样,不能精确唤醒线程。 六:从性能比较 生活小case理解:在我们一般的认知中,官二代一般都是比较坑爹的吧。但是这几年也有很多官二代或者是富二代改变了态度,端正自己态度,靠自己能力而不是拼爹了。 七:从使用锁的方式比较 欢迎来聊~

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册