barriers / 阅读 / 详情

java.util.concurrent.Future.isDone是否有必要

2023-07-16 19:19:52
共1条回复
马老四

有必要,因为get方法会一直等待资源返回,可以用isDone判断

Future.get()方法会一直阻塞,直到有数据返回,这时候isDone()是true.那么在get()之前判断isDone()是否有必要?如下:

if (!future.isCancelled())

{

HotelSearchResponse response = null;

if (future.isDone()) //这里有没有必要判断

{

if (future.get() != null)

{

response = future.get();

}

else

{

while (!future.isDone())//这个while有没有必要

{

if (future.get() != null)

{

response = future.get();

}

}

}

}

相关推荐

concurrent是什么意思

concurrentadj.〈正式〉同时发生的; 同时完成的; 同时存在的; n.[数] 共点; 同时发生的事件; **************************************************************如果你对这个答案有什么疑问,请追问,另外如果你觉得我的回答对你有所帮助,请千万别忘记采纳哟!***************************************************************
2023-07-16 15:45:372

concurrent与simultaneous的区别

concurrent [ku0259n"ku028cru0259nt] adj. 并发的;一致的;同时发生的n. 共点;同时发生的事件simultaneous [,simu0259l"teiniu0259s] adj. 同时的;联立的;同时发生的n. 同时译员
2023-07-16 15:45:461

ConcurrentHashMap如何实现高效地线程安全?

读的时候用volatile保证可见性,使读到的数据永远是最新的写的时候用分段锁只对部分数据加锁
2023-07-16 15:45:542

简单总结ConcurrentHashMap

在并发使用到HashMap的时候,往往不建议直接用HashMap,因为HashMap在并发写数据的时候容易因为rehash的过程产生环形链表的情况。所以在并发使用Map结构时,一般建议使用ConcurrentHashMap。 在JDK1.7中ConcurrentHashMap采用了 数组+Segment+分段锁 的方式实现。 从上面的结构我们可以了解到,ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作。第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。 JDK8中ConcurrentHashMap参考了JDK8 HashMap的实现,采用了数组+链表+红黑树的实现方式来设计,内部大量采用CAS操作。并发控制使u2f64 synchronized 和 CAS 来操作。 (JDK1.6 以后 对 synchronized 锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在 JDK1.8 中还能看到 Segment 的数据结构,但 是已经简化了属性,只是为了兼容旧版本; JDK1.8的Nod节点中value和next都用volatile修饰,保证并发的可见性。 可以理解为,synchronized 只锁定当前链表或红u2fcau2f06叉树的u2fb8节点,这样只要 hash 不冲突,就不会产u2f63并发,效率u2f1c提升 N 倍。 Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采u2f64 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突u2f7d存在的; Hashtable(同u2f00把锁) :使u2f64 synchronized 来保证线程安全,效率u2fae常低下。当u2f00个线程访问同步u2f45法时,其他线程也访问同步u2f45法,可能会进u2f0a阻塞或轮询状态,如使u2f64 put 添加元素,另u2f00个线程不能使u2f64 put 添加元素,也不能使u2f64get,竞争会越来越激烈效率越低; 总结一下: JavaGuide
2023-07-16 15:46:091

concurrentmap为什么线程安全

concurrentmap线程安全原因:1、JDK1.7中,ConcurrentHashMap使用的锁分段技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。2、JDK1.8放弃了锁分段的做法,采用CAS和synchronized方式处理并发。以put操作为例,CAS方式确定key的数组下标,synchronized保证链表节点的同步效果。
2023-07-16 15:46:161

HashMap、HashTable、ConcurrentHashMap的原理与区别

从类图中可以看出来在存储结构中ConcurrentHashMap比HashMap多出了一个类Segment。 ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一个可重入锁(ReentrantLock),在ConcurrentHashMap里扮演锁的角色;HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组。Segment的结构和HashMap类似,是一种数组和链表结构。一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素,每个Segment守护着一个HashEntry数组里的元素。当对HashEntry数组的数据进行修改时,必须首先获得与它对应的segment锁。 ConcurrentHashMap是使用了锁分段技术来保证线程安全的。 锁分段技术 :首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。 ConcurrentHashMap提供了与Hashtable和SynchronizedMap不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。 Hashtable容器在竞争激烈的并发环境下表现出效率低下的原因是因为所有访问Hashtable的线程都必须竞争同一把锁,假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术。首先将数据分成一段一段存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其它段的数据也能被其它线程访问。
2023-07-16 15:46:241

hashmap和concurrenthashmap的区别是什么?

hashmap和concurrenthashmap的区别如下:HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在。那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。HashMap:底层数组+链表实现,可以存储null键和null值,线程不安全。初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂。扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入。插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)。ConcurrentHashMap:底层采用分段的数组+链表实现,线程安全。通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)。Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。
2023-07-16 15:46:311

jdk8中的ConcurrentHashMap究竟为什么高效?

从源码来窥其一斑! 我们都知道hashMap不是线程安全的,因为在扩容方法中很容易出现死循环,hashTable使用锁的方式比较简单暴力,几乎在所有操作方法上都加了synchronized锁,导致总体性能很差,concurrentHashmap凭借线程安全且性能优异一直都是高并发中的首选key-value型数据结构; concurrentHashmap的高性能有以下原因: 一,分段锁:jdk8中对concurrentHashmap进行了改进,抛弃了jdk7中新建segment作为分段锁的过程,jdk8中虽沿用了这种分段锁的思想,却直接使用数组中的数据作为 分段锁保证concurrentHashmap在上锁的时候只针对数组下标下的数据进行上锁 (比如如果数组长度为256,那么每次put平均只有1/256的数据被锁),而大多数其他的数据还是能进行正常的增删改操作,无需阻塞等待,这无疑极大的 降低了锁的粒度,提升了性能。 二,红黑树 :jdk8中引入了红黑树结构,在单个数组下标内的数据达到8以后,会自动转换为红黑树进行存储, 使用大O表示法表示效率的话,红黑树的查找效率为O(log(n)),而链表的效率为O(n) ,当数据量越来越大的时候,红黑树的效率明显好于链表,所以concurrentHashmap性能得到很大提升; 现在我们主要从put方法中的主要方法来分析性能的提升: spread(key.hashCode());//作用是再次哈希,减少冲突 ,源码如下其中涉及到的位运算有 >>> 16:无符号右移16位,空位以0补齐 。 ^:异或运算符-->相同为0,不同为1; &:与运算符-->全1得1,否则0; (h ^ (h >>> 16)) & HASH_BITS; 所以这句代码的意思就是不仅消除高16位的影响,同时获得正整数的hash值 再来看后面的方法, 如上图: 1,就是判断当这个hash表还是空的时候,调用initTable进行初始化; 2,使用(n - 1) & hash)计算数组下标,如果数据指定下标处为null,则直接插入,注: cas是java8中的concurrentHashmap引入的线程安全判断,CAS算法做为乐观锁 ; 3,(fh = f.hash) == MOVED,走到此处说明下标内有node,且该node的值为-1(MODED=-1),搜索全类发现MODED是在调用有参构造器ForwardingNode中默认写入的,而这个调用处刚好在transfer方法中,所以我们推断,扩容的时候先将数组下标内的node.hash置为-1! 同时在3这一步中调用helpTransfer(tab, f)参与扩容,并把数据写入;4,走到这说明node不是空的,也没在扩容,那么锁住该下标下的node,并把新value插入链表中; 5,如果锁住的这个node能实例化为TreeBin,则代表已经转化为红黑树进行存储,将数据插入红黑树中; 6,判断在4,5中计算得到的数组下标内所有节点总数, 如果满足转化为红黑树的条件(节点数大于8),则自动转化为红黑树进行存储! 总的来说,concurrentHashmap之所以性能高就是因为使用了分段锁和红黑树! 至于conrrentHashmap其他的方法的源码分析,后期会补上的,更多的技术分享,敬请关注!
2023-07-16 15:46:441

concurrent with是什么意思

同时 一致
2023-07-16 15:47:102

ConcurrentHashMap常问问题

采用了分段锁的思想,将哈希桶数组分成一个个的Segment数组(继承ReentrantLock),每一个Segment里面又有多个HashEntry,也是被volatile修饰的,是为了保证在数组扩容时候的可见性,HashEntry中又有key,hash,value,next属性,而value,next又是被volatile修饰为了保证多线程环境下数据修改时的可见性,多线程环境下ConcurrentHashMap会对这些小的数组进行加锁,这样多线程操作Map就相当于是操作单线程环境下的HashMap,比如A线程对其中一个段进行写操作的时候线程B就不能对其进行写操作,但是线程B可以对其他的段进行写操作,从而实现并发修改和访问。 JDK1.8的ConcurrentHashMap摒弃了分段锁的思想,采用jdk1.8中HashMap的底层机构,Node数组+链表+红黑树。Node是继承了Entry的一个内部类,他的value和next都是被volatile修饰的原因也是为了保证多线程下修改数据的可见性。 采用CAS+synchronized实现更加细粒度的锁,将锁的级别控制在更细粒度的哈希桶数组元素的级别,只需要锁住链表头节点(红黑树的根节点)就不会影响到其他哈希桶数组元素的读写,大大的提高了并发度。 是不需要加锁的,因为Node节点使用了volatile修饰了value和next节点,而在jdk8中同样也是使用了volatile修饰了value和next节点,这样保证可见性了就不需要加锁了。 key不能为空,无法解释,没有什么可说的,可能就是作者的想法。 value不能为空是因为ConcurrentHashMap是工作在多线程环境下的,如果调用get方法,返回null,这个时候就存在二义性,因为ConcurrentHashMap不知道是没有这个key,还是这个key对应的值是不是null。所以干脆不支持value为null。 HashMap的迭代器是强一致性的,而ConcurrentHashMap的迭代器是弱一致性的,因为在多线程环境下,在创建迭代器的过程中,内部的元素会发生变化,如果是在已经遍历过去的数据中发生变化,迭代器是无法反映出来数据发生了改变,如果是发生在未迭代的数据时,这个时候就会反映出来,强一致性就是说只要迭代器创建出来之后数据就不会发生改变了。这样设计的好处就是迭代器线程可以使用原来的老数据进行遍历,写线程可以并发的完成改变,这样就保证了多个线程执行的时候的连续性和可拓展性,提升了并发性能。 JDK1.7中,并发度就是ConcurrentHashMap中的分段个数,即Segment[]数组的长度,默认是16,这个值可以在构造函数中设置。如果自己设置了并发度那么就会和HasHMap一样会去找到大于等于当前输入值的最小的2的幂指数作为实际并发度。如果过小就会产生锁竞争,如果过大,那么就会导致本来位于同一个Segment的的访问会扩散到不同的Segment中,导致性能下降。 JDK1.8中摈弃了Segment的概念,选择使用HashMap的结构,并发度依赖于数组的大小。 ConcurrentHashMap效率高,因为hashTable是给整个hash表加锁,而ConcurrentHashMap锁粒度要更低。 使用Collections.synchronizedMap(Map类型的对象)方法进行同步加锁,把对象转换为SynchronizedMap<K,V>类型。其实就是对HashMap做了一次封装,多个线程竞争一个mutex对象锁,在竞争激烈的情况下性能也非常差,不推荐使用。
2023-07-16 15:47:171

concurrent.futures 模块怎么安装 或者concurrent 模块也可以

如果是python2.x,直接在命令提示符中用pip install futures语句安装,concurrent就可以用了。如果是python3,不用安装也可以用,自带了。参看:https://stackoverflow.com/questions/31086530/importerror-no-module-named-concurrent-futures-process
2023-07-16 15:47:252

ConcurrentHashMap面试问题总结

Q:ConcurrentHashMap和HashMap的区别是什么? A: 1.ConcurrentHashMap是线程安全的,HashMap是线程不安全的 2.ConcurrentHashMap不允许Key为null的值插入。而HashMap是可以的 Q:JDK8的ConcurrentHashMap和JDK7的ConcurrentHashMap有什么区别? A: 1.JDK7的ConcurrentHashMap采用分段锁的策略,将整个数组分成多个segment,对这些segment进行分段加锁,使用的锁是ReentrantLock。而JDK8中的ConcurrentHashMap不采用分段锁的方式,直接使用Synchronized来进行。 2.JDK8中的ConcurrentHashMap新增了红黑树,并且插入用的是尾插法。 3.JDK7中的ConcurrentHashMap进行扩容时,是对当前的segment进行扩容,不会对其他segment有影响。而JDK8中就跟HashMap一样。整体扩容,但是保证线程安全 Q:JDK7中的ConcurrentHashMap是如何扩容的 A:JDK7中对每一段segment进行扩容,每一段segment的扩容跟HashMap保持一致 Q:JDK8中的ConcurrentHashMap是如何扩容的 A:在扩容时,首先会生成一个双倍大小的数组,生成完数组后,线程就会开始转移元素,在扩容的过程中,如果有其他线程在put,那么这个put线程会帮助去进行元素的转移,虽然叫转移,但是其实是基于原数组上的Node信息去生成一个新的Node的,也就是原数组上的Node不会消失,因为在扩容的过程中,如果有其他线程在get也是可以的。 Q:ConcurrentHashMap是如何保证线程安全的 A: 1.在JDK7的时候。ConcurrentHashMap是通过ReentrantLock+CAS+分段思想来保证的并发安全的,在JDK7的ConcurrentHashMap中,首先有一个Segment数组,存的是Segment对象,Segment相当于一个小HashMap,Segment内部有一个HashEntry的数组,也有扩容的阈值,同时Segment继承了ReentrantLock类,同时在Segment中还提供了put,get等方法,比如Segment的put方法在一开始就会去加锁,加到锁之后才会把key,value存到Segment中去,然后释放锁。同时在ConcurrentHashMap的put方法中,会通过CAS的方式把一个Segment对象存到Segment数组的某个位置中。同时因为一个Segment内部存在一个HashEntry数组,所以和HashMap对比来看,相当于分段了,每段里面是一个小的HashMap,每段公用一把锁,同时在ConcurrentHashMap的构造方法中是可以设置分段的数量的,叫做并发级别concurrencyLevel. 2.在JDK8的时候,ConcurrentHashMap是通过synchronized+cas来实现了。在JDK8中只有一个数组,就是Node数组,Node就是key,value,hashcode封装出来的对象,和HashMap中的Entry一样,在JDK8中通过对Node数组的某个index位置的元素进行同步,达到该index位置的并发安全。同时内部也利用了CAS对数组的某个位置进行并发安全的赋值。
2023-07-16 15:47:321

同时地英语怎么说

问题一:在同时的英语表达 同时 的 六种表达法: at the same time meanwhile in the meantime simultaneously moreover besides 问题二:在 ....的同时 英语怎么说 While During 问题三:同时的英语短语怎么讲 一边忙于毕业论文一边找工作 I"m busy with my paper as well as finding a job 问题四:“与此同时”的英文怎么说 “与此同时”在英文里有多种表达方式,根据句式而有所不同,如下将分别举例说明: Meanwhile是副词,一般用于句首; at the same time作状语,一般放在句末; 除此以外,还可以用修饰动词的副词concurrently,表达“同时(做)...”的意思。例句:Furthermore, all these dharmas are to be understood as concurrently present in the dharmadhatu. From 问题五:“一起”的英语怎么说 不同的语境用法不同: 单纯的一起就是together, 一对恋人在一起(我想和你一起I wanna be with you) 一起走(I want you to e with me 我想让你和我一起走)量词,比如“一起事件 an incidence 问题六:同时发生的的英文,同时发生的的翻译,怎么用英语翻译 同时发生的 simultaneous;concurrent;instantaneous;coinstantaneous更多释义>> [网络短语] 同时发生的 simultaneous;concurrent;coinstantaneous 同时发生的事件 concurrent 同时发生的概率 PF,E 问题七:”在提高性能的同时“英语怎么说 While improving performance,... 问题八:问题与解决问题的方法总是同时存在。 用英语怎么说,不要百度翻译的。 Solutions always e with questions. 问题九:和......在一起用英语怎么说 be with *** 和谁在一起 例如 I want to be with you。 我想和你在一起 do sth with *** 和某人一起做某事 例如 I do homework with you 我和你一起做功课 do sth with sth 用某事来做某事 例如 I wash the clothes with water 我用水洗衣服 希望可以帮到你
2023-07-16 15:47:391

如何在java中使用ConcurrentHashMap

参考如下内容:ConcurrentHashMap锁的方式是稍微细粒度的。 ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。试想,原来 只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。更令人惊讶的是ConcurrentHashMap的读取并发,因为在读取的大多数时候都没有用到锁定,所以读取操作几乎是完全的并发操作,而写操作锁定的粒度又非常细,比起之前又更加快速(这一点在桶更多时表现得更明显些)。只有在求size等操作时才需要锁定整个表。而在迭代时,ConcurrentHashMap使用了不同于传统集合的快速失败迭代器的另一种迭代方式,我们称为弱一致迭代器。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出 ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数 据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。下面分析ConcurrentHashMap的源码。主要是分析其中的Segment。因为操作基本上都是在Segment上的。先看Segment内部数据的定义。
2023-07-16 15:47:461

如何正确使用QtConcurrent运行类成员函数

使用QtConcurrent的代码如下:void MainDialog::on_pushButton_toGrayImage_QConcurrent_clicked(){ QFuture<QImage*> future = QtConcurrent::run(this,&MainDialog::processImageByQtConcurrent); //imageAfterProceess 这个指针变量之前被无视,现在终于找到存在感了 this->imageAfterProceess = future.result(); //接收处理结果 this->showImageInNewWindow(this->imageAfterProceess);//新窗口显示处理后的图像}
2023-07-16 15:48:072

java concurrenthashmap和hashmap的区别

即使是线程安全的集合,使用iterator()进行迭代都是不安全的,必须手动地进行同步,下面是JavaDoc的说明:Itisimperativethattheusermanuallysynchronizeonthereturnedmapwheniteratingoveranyofitscollectionviews:Mapm=Collections.synchronizedMap(newHashMap());Sets=m.keySet();//Needn"tbeinsynchronizedblocksynchronized(m){//Synchronizingonm,nots!Iteratori=s.iterator();//Mustbeinsynchronizedblockwhile(i.hasNext())foo(i.next());}如果不使用同步块进行迭代,当在迭代时,如果存在另外一个线程对集合进行删除或者添加元素,则会报ConcurrentModificationException
2023-07-16 15:48:183

如何正确使用QtConcurrent运行类成员函数

使用QtConcurrent的代码如下:void MainDialog::on_pushButton_toGrayImage_QConcurrent_clicked(){ QFuture<QImage*> future = QtConcurrent::run(this,&MainDialog::processImageByQtConcurrent); //imageAfterProceess 这个指针变量之前被无视,现在终于找到存在感了 this->imageAfterProceess = future.result(); //接收处理结果 this->showImageInNewWindow(this->imageAfterProceess);//新窗口显示处理后的图像}
2023-07-16 15:48:381

java.util.concurrent.cancellationexception怎么解决

uservo user=(uservo)voinfo;String username=user.getUsername();String password=user.getPassword();System.out.println("your username is "+username);System.out.println("your password is "+password);List list = new ArrayList();
2023-07-16 15:48:471

Concurrent包中线程池问题:java中主函数执行完了为什么主线程还没有退出?是因为啥?都已经输出了横杠了.

那是因为你线程池没有关闭,所以主线程就不会退出,需要主线程退出只需要调用线程池的shutdown()方法,你的代码可以在main方法的最后一行加上 thr.shutdown(); 就可以了。
2023-07-16 15:48:551

为什么CMS GC时出现Concurrent Mode Failure

并发收集器(concurrentcollector)指的是回收年老代和持久代时,采用多个线程和应用线程并发执行,减少应用停顿时间,但如果参数设置不当,容易出现Concurrent ModeFailure现象,此时JVM将采用停顿的方式进行full gc,整个gc时间相当可观,完全违背了采用CMS GC的初衷。 出现此现象的原因主要有两个:一个是在年老代被用完之前不能完成对无引用对象的回收;一个是当新空间分配请求在年老代的剩余空间中得到满足。原文如(if theconcurrent collector is unable to finish reclaiming the unreachable objectsbefore the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped)。出现此现象的具体gc日志如下:90003.167: [GC 90003.167: [ParNew: 261760K->0K(261952K), 0.0204310secs] 778897K->520196K(1310528K), 0.0207190 secs]90006.049: [GC 90006.050: [ParNew: 261760K->0K(261952K), 0.0136380 secs]781956K->521446K(1310528K), 0.0138720 secs]90010.628: [GC 90010.628: [ParNew: 261760K->261760K(261952K), 0.0000350secs]90010.628: [CMS (concurrent mode failure)[Unloadingclass sun.reflect.GeneratedSerializationConstructorAccessor1818][Unloading class sun.reflect.GeneratedSerializationConstructorAccessor1816][Unloading class sun.reflect.GeneratedSerializationConstructorAccessor1819][Unloading class sun.reflect.GeneratedSerializationConstructorAccessor1821][Unloading class sun.reflect.GeneratedSerializationConstructorAccessor1817][Unloading class sun.reflect.GeneratedSerializationConstructorAccessor1822][Unloading class sun.reflect.GeneratedSerializationConstructorAccessor1820]: 521446K->415777K(1048576K), 2.2550270 secs] 783206K->415777K(1310528K),2.2553820 secs]90015.099: [GC 90015.099: [ParNew: 261760K->0K(261952K), 0.0198180 secs]677537K->418003K(1310528K), 0.0200650 secs]90018.670: [GC 90018.670: [ParNew: 261760K->0K(261952K), 0.0131610 secs]679763K->419115K(1310528K), 0.0133750 secs]90022.254: [GC 90022.254: [ParNew: 261760K->0K(261952K), 0.0151240 secs]680875K->420505K(1310528K), 0.0154180 secs]当时的JVM参数如下:-server -Xms1280m -Xmx1280m -Xmn256m -Xss256k -XX:PermSize=128m-XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC-XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled-XX:+DisableExplicitGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps因为配置了+CMSClassUnloadingEnabled参数,所以出现Unloading classsun.reflect.GeneratedSerializationConstructorAccessor的日志,这是个好习惯,如果空间不够时可以卸载类来释放空间,以进行FULL GC,相反,如果gc日志中出现了此日志,应该检查各代的大小设置是否合理。这里应用从启动到上述现象出现时还没有进行过CMS GC,出现concurrent modefailure现象的原因是年轻代GC(ParNew),年老代所剩下的空间不足以满足年轻代,也就是开头提到的原因二。要避免此现象,方法一是降低触发CMS的阀值,即参数-XX:CMSInitiatingOccupancyFraction的值,默认值是68,所以这里调低到50,让CMS GC尽早执行,以保证有足够的空间,如下:-server -Xms1280m -Xmx1280m -Xmn256m -Xss256k -XX:PermSize=128m-XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC-XX:CMSFullGCsBeforeCompaction=1 -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=50-XX:+CMSClassUnloadingEnabled -XX:+DisableExplicitGC -verbose:gc-XX:+PrintGCDetails -XX:+PrintGCTimeStamps调完之后发现还是一样的现象(这里有点不是很明白,年老代空间为1024m(1280m-256m),50%时触发CMS GC,也就是在年老代512m的时候,剩下的堆空间有512m,就算年轻代全部装进去应该也是够的),所以怀疑是年轻代太大,有大的对象,在年老代有碎片的情况下将很难分配,所以有了第二个解决办法,即减少年轻代大小,避免放入年老代时需要分配大的空间,同时调整full gc时压缩碎片的频次,减少持久代大小,以及将触发CMS GC的阀值适当增大(因为年轻代小了,这个调大点没关系,后面可以再调试这个参数),参数如下:-server -Xms1280m -Xmx1280m -Xmn128m -Xss256k -XX:PermSize=96m -XX:MaxPermSize=96m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSFullGCsBeforeCompaction=1 -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSClassUnloadingEnabled -XX:+DisableExplicitGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps调整完后没有那个现象了,这里主要起作用的就是调小年轻代大小。在年老代到达826m(触发CMS阀值(1280-128)*0.7=806m)时出现了CMS GC,用时27ms,日志如下:705.444: [GC 705.445: [ParNew: 130944K->0K(131008K), 0.0197680 secs]954628K->826284K(1310656K), 0.0199720 secs]705.467:[GC [1 CMS-initial-mark: 826284K(1179648K)] 826744K(1310656K), 0.0271540 secs]705.494:[CMS-concurrent-mark-start]706.717:[CMS-concurrent-mark: 1.223/1.223 secs]706.717:[CMS-concurrent-preclean-start]706.717:[CMS-concurrent-preclean: 0.000/0.000 secs]706.742:[CMS-concurrent-abortable-preclean-start]706.742:[CMS-concurrent-abortable-preclean: 0.000/0.000 secs]707.067: [GC 707.067: [ParNew: 130944K->0K(131008K), 0.0160200 secs]957228K->827348K(1310656K), 0.0162110 secs]707.796: [GC[YG occupancy: 66671 K (131008 K)]707.796: [Rescan (parallel) ,0.0278280 secs]707.824: [weak refs processing, 0.0420770 secs] [1 CMS-remark:827348K(1179648K)] 894019K(1310656K), 0.0711970 secs]707.877: [CMS-concurrent-sweep-start]708.453: [GC 708.454: [ParNew: 130944K->0K(131008K), 0.0203760 secs]848439K->718796K(1310656K), 0.0205780 secs]709.833: [GC 709.833: [ParNew: 130944K->0K(131008K), 0.0160170 secs]430484K->301411K(1310656K), 0.0161840 secs]709.916: [CMS-concurrent-sweep: 1.974/2.040 secs]709.916: [CMS-concurrent-reset-start]709.951: [CMS-concurrent-reset: 0.034/0.034 secs]711.187: [GC 711.187: [ParNew: 130944K->0K(131008K), 0.0130890 secs]413136K->283326K(1310656K), 0.0132600 secs]观察一段时间的gc情况,gc效率也很高,单次YGCT<20ms,FGCT <40ms:$ jstat -gcutil 31935 1000 S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 0.00 64.29 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.33 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.41 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.45 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.49 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.58 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.63 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.69 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.72 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.75 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.79 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.84 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.90 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.95 36.47 73.15 1293 19.514 6 0.211 19.725 0.00 0.00 64.99 36.47 73.15 1293 19.514 6 0.211 19.725这时,想再测试下-XX:CMSInitiatingOccupancyFraction的值,调到80时又出现了上述现象Concurrent ModeFailure,启动后还没进行过CMS GC,在年老代914m时就出现了:759.994: [GC 759.994: [ParNew: 130944K->0K(131008K), 0.0172910 secs]1040896K->911480K(1310656K), 0.0174730 secs]760.879: [GC 760.879: [ParNew: 130944K->0K(131008K), 0.0300920 secs]1042424K->914190K(1310656K), 0.0302950 secs]761.768: [GC 761.769: [ParNew: 130944K->130944K(131008K), 0.0000340secs]761.769: [CMS (concurrent mode failure)[Unloading classsun.reflect.GeneratedMethodAccessor342]edMethodAccessor348][Unloading class sun.reflect.GeneratedMethodAccessor411][Unloading class sun.reflect.GeneratedMethodAccessor407][Unloading class sun.reflect.GeneratedMethodAccessor541]最后总结下,出现Concurrent ModeFailure现象时,解决办法就是要让年老代留有足够的空间,以保证新对象空间的分配。另外在JVM BUG中有提到,JDK1.5_09版本之前,JVM参数-XX:CMSInitiatingOccupancyFraction是无效的,我这里应用环境的版本是JDK1.5_08,从gc日志来看是可以生效的。GC时还有一个常见的错误PromotionFailed,解决办法类似,也是调整年轻代和年老代的比例,还有CMSGC的时机。
2023-07-16 15:49:021

为什么java.util.concurrent 包里没有并发的ArrayList实现

你包引错了吧,让他自动引,如果还没有就是版本低了,要1.5还是1.6后面才有这个
2023-07-16 15:49:112

java.util.concurrent.atomic的可变规则

原子访问和更新的内存效果一般遵循以下可变规则:get 具有读取 volatile 变量的内存效果。set 具有写入(分配) volatile 变量的内存效果。weakCompareAndSet 以原子方式读取和有条件地写入变量,并对于该变量上的其他内存操作进行排序,否则将充当普通的非可变内存操作。compareAndSet 和所有其他的读取和更新操作(如 getAndIncrement)都有读取和写入 volatile 变量的内存效果。除了包含表示单个值的类之外,此包还包含 Updater 类,该类可用于获取任意选定类的任意选定 volatile 字段上的 compareAndSet 操作。AtomicReferenceFieldUpdater、AtomicIntegerFieldUpdater 和 AtomicLongFieldUpdater 是基于反射的实用工具,可以提供对关联字段类型的访问。它们主要用于原子数据结构中,该结构中同一节点(例如,树节点的链接)的几个 volatile 字段都独立受原子更新控制。这些类在如何以及何时使用原子更新方面具有更大的灵活性,但相应的弊端是基于映射的设置较为拙笨、使用不太方便,而且在保证方面也较差。AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray 类进一步扩展了原子操作,对这些类型的数组提供了支持。这些类在为其数组元素提供 volatile 访问语义方面也引人注目,这对于普通数组来说是不受支持的。AtomicMarkableReference 类将单个布尔值与引用关联起来。例如,可以在数据结构内部使用此位,这意味着引用的对象在逻辑上已被删除。AtomicStampedReference 类将整数值与引用关联起来。例如,这可用于表示与更新系列对应的版本号。
2023-07-16 15:49:181

concurrenthashmap是线程安全的吗

这样使用是有问题的。ConcurrentMap能够保证每一次调用(例如一次putIfAbsent)都是原子操作,不受多线程影响,但并不保证多次调用之间也是原子操作。以上实现的GetKeyBM方法中,ConcurrentMap的方法被调用了许多次,不同线程之间必然存在着竞争关系,导致最终结果不正确。现在的目标是,将下面描述的这一系列操作作为原子操作:“对每个分出来的词通过调用GetKeyBM方法,如果存在,则取出对应的编码,如果不存在,则加入KeyTotal中,并且给予一个编码,就是KeyTotal中的变量数加一”最直观的方法就是整块同步:synchronized (KeyTotal) {Integer value = KeyTotal.get(word);if (value == null) {value = KeyTotal.size() + 1;KeyTotal.put(word, value);}}这样,使用普通的map就可以了。如果你使用的是Java 8的话,ConcurrentMap有一个类似的方法 computeIfAbsent 可以使用:KeyTotal.computeIfAbsent(word, k -> KeyTotal.size() + 1);这样才能确保一次原子操作。computeIfAbsent方法的作用是,如果word键值不存在,则使用第二个参数来生成一个值放入map中,等价于以下代码,并且是原子操作:V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction):if (map.get(key) == null) {V newValue = mappingFunction.apply(key);if (newValue != null)return map.putIfAbsent(key, newValue);}正好与你的目标是一致的。
2023-07-16 15:49:321

ConCurrentHashMap 1.7 和 1.8 的区别

ConCurrentHashMap 1.8 相比 1.7的话,主要改变为: 下面简单介绍下主要的几个方法的一些区别: JDK1.7中的实现: ConCurrentHashMap 和 HashMap 的put()方法实现基本类似,所以主要讲一下为了实现并发性,ConCurrentHashMap 1.7 有了什么改变 JDK1.8中的实现: JDK1.7中的实现: JDK1.8中的实现: JDK1.7中的实现: JDK1.8中的实现: JDK1.7中的实现: JDK1.8中的实现: 由于没有segment的概念,所以只需要用一个 baseCount 变量来记录ConcurrentHashMap 当前 节点的个数 。
2023-07-16 15:49:391

HashMap HashTable和ConcurrentHashMap的区别

最大的区别就是ConcurrentHashMap是线程安全的,hashMap不是线程安全的。为什么线程安全呢:ConcurrentHashMap代码中可以看出,它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中:
2023-07-16 15:49:482

为什么CMS GC时出现Concurrent Mode Failure

出现Concurrent ModeFailure现象时,解决办法就是要让年老代留有足够的空间,以保证新对象空间的分配。另外在JVM BUG中有提到,JDK1.5_09版本之前,JVM参数-XX:CMSInitiatingOccupancyFraction是无效的,我这里应用环境的版本是JDK1.5_08,从gc日志来看是可以生效的。GC时还有一个常见的错误PromotionFailed,解决办法类似,也是调整年轻代和年老代的比例,还有CMSGC的时机。
2023-07-16 15:50:221

为什么java.concurrent.automic 里面没有string

因为String不是基础类型,而是对象,且是个Value Object(值对象)。你无法改变一个String对象的内容,你只能用另一个String的对象来替换原有的引用。例如:int i = 0;i++;//改变了原来的值String s = "xxx";//你无法改变原来的值s = "abc";//只能使用另外一个对象来替换因此atomic封装的String没有任何用处。atomic包是工具包,只是提供一个方便处理并发计数、改变标志的工具类,不能替代原来的基础类型和对象使用。
2023-07-16 15:50:291

hashmap和concurrenthashmap哪个是线程安全的,为什么线程安全

ConcurrentHashMap是线程安全的,而HashMap不是线程安全的。在多线程环境下,如果多个线程同时读写同一个HashMap对象,可能会导致数据不一致的问题,例如两个线程同时往HashMap中添加数据,可能会导致数据丢失或覆盖。这是因为HashMap的实现不是线程安全的,它的内部结构是由数组和链表组成的,多个线程同时对它进行操作,会导致链表形成环形或链表断裂,导致数据读取或修改错误。ConcurrentHashMap是线程安全的原因是它采用了分段锁的机制,将HashMap分成若干个段(Segment),每个Segment独立地加锁,不同的线程可以同时访问不同的Segment,从而避免了多个线程同时访问同一个Segment的情况。这种机制可以提高并发访问效率,保证了线程安全性。
2023-07-16 15:50:361

concurrenthashmap的读是否要加锁,为什么

。有并发访问的时候用ConcurrentHashMap,效率比用锁的HashMap好功能上可以,但是毕竟ConcurrentHashMap这种数据结构要复杂些,如果能保证只在单一线程下读写,不会发生并发的读写,那么就可以试用HashMap。ConcurrentHashMap读不加锁,写只加部分锁。在多线程下得高性能读写用比较好。但是这也是要用空间换时间来的。如果我的回答没能帮助您,请继续追问。
2023-07-16 15:50:441

A child container failed during start。 tomcat启动报错

遇到这个问题的小伙伴,看看是不是和我遇到的问题一样。(问题已解决)我本地环境项目好的,但是我同事的却报:A child container failed during start最后我将我本地打成的war包和他打成的war包内的jar包对比,发现bcprov-jdk16这个包不一样。使用bcprov-jdk16包 需要在本地运行的时候 如果出现找不到某某类的时候 需要将这个jar包加入jre环境下,将bcprov-jdk16-146.jar 放入 本机 jre/lib/ext 下 即可。(本句来自:网页链接)然后就正常了。
2023-07-16 15:50:523

concurrenthashmap支持高并发的原理,段锁为什么要采用重入锁而不是synchronized

ConcurrentHashMap只是保证本身map的线程安全,不保证你自己写的程序的同步.你可以采用客户端加锁实现同步synchronized(test.chm)
2023-07-16 15:51:161

concurrent.jar 包是做什么用的

jar包就是别人已经写好的一些类,然后将这些类进行打包,你可以将这些jar包引入你的项目中,然后就可以直接使用这些jar包中的类和属性了,这些jar包一般都会放在lib目录下的...呵呵
2023-07-16 15:51:231

java8 中concurrenthashmap数据结构和HashMap一样,且线程安全 为什么还要HashMap

java是编程语言里比较难学的一门,如果有心从事编程方向的工作,最好到专业机构学习并有更多的项目实践,更贴近市场,这样更有利于将来的发展。
2023-07-16 15:51:345

为什么java.util.concurrent包没有concurrentList

有个CopyOnWriteArrayList
2023-07-16 15:52:022

ConcurrentHashMap内部排序的使用

业务中,我们经常会有队map进行排序的要求,如下将会详细讲解如何利用java8的lambda表达式实现map的内部排序。 首先,我们先构造一个person类: public class Person { private String addr; private String age; } 测试,对map进行排序处理。 import com.ky.common.Person; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.Map.Entry.comparingByValue; import static java.util.stream.Collectors.toMap; public class Test { stream.sorted(Comparator.comparingInt(Map.Entry::getValue)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2)->e2, ConcurrentHashMap::new)); map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue)).forEach(System.out::println); }
2023-07-16 15:52:091

如何正确使用QtConcurrent运行类成员函数

使用QtConcurrent的代码如下:void MainDialog::on_pushButton_toGrayImage_QConcurrent_clicked(){QFuture<QImage*> future = QtConcurrent::run(this,&MainDialog::processImageByQtConcurrent);//imageAfterProceess 这个指针变量之前被无视,现在终于找到存在感了this->imageAfterProceess = future.result(); //接收处理结果this->showImageInNewWindow(this->imageAfterProceess);//新窗口显示处理后的图像}
2023-07-16 15:52:441

collections.synchronizedmap和concurrenthashmap的区别

最大的区别就是ConcurrentHashMap是线程安全的,hashMap不是线程安全的。为什么线程安全呢:ConcurrentHashMap代码中可以看出,它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中:
2023-07-16 15:53:081

backport-util-concurrent是什么

backport-util-concurrent.jar并发访问处理端口的工具包。是LCDS的一部分
2023-07-16 15:53:161

java.util.concurrent.Future.isDone是否有必要

有必要,因为get方法会一直等待资源返回,可以用isDone判断 Future.get()方法会一直阻塞,直到有数据返回,这时候isDone()是true.那么在get()之前判断isDone()是否有必要?如下: if (!future.isCancelled()) { HotelSearchResponse response = ...
2023-07-16 15:53:331

concurrent session是什么意思

并行会议
2023-07-16 15:53:524

aix 如何判断vg是concurrent

比较vg的pvid,如果一样,说明这个vg是shared,算是concurrent
2023-07-16 15:54:001

java开发 怎么控制 每秒并发数?

java.util.concurrent.Executors里有很多方法创建固定个数的线程池使用线程池应该可以吧
2023-07-16 15:54:082

newfixedthreadpool 怎么控制超时的线程

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。看代码:Java代码 收藏代码<span style="font-size: small;">package test;import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;public class ExecutorTest {public static void main(String args[]) {Random random = new Random();//产生一个 ExecutorService 对象,这个对象带有一个大小为 poolSize 的线程池,若任务数量大于 poolSize ,任务会被放在一个 queue 里顺序执行。ExecutorService executor = Executors.newFixedThreadPool(3);// 判断可是线程池可以结束int waitTime = 500;for (int i = 0; i < 10; i++) {String name = "线程 " + i;int time = random.nextInt(1000);waitTime += time;Runnable runner = new ExecutorThread(name, time);System.out.println("增加: " + name + " / " + time);executor.execute(runner);}try {Thread.sleep(waitTime);executor.shutdown();executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);} catch (InterruptedException ignored) {}} }
2023-07-16 15:54:161

verilog 编译错误:Concurrent assignment to a non-net registerr is not permitted

调用子模块时 输出端口只能用wire类型变量进行映射 这是verilog语法规定的不知道你说的“无法实现想要的功能”是指什么 但是如果你需要输出信号是reg类型可以增加一个wire类型中间变量 再把这个中间变量赋值给一个reg类型变量wire a;testmodule tss(dataa,a,clockk);reg registerr;always @ * registerr <= a;
2023-07-16 15:54:242

ConcurrentHashMap 中putIfAbsent 和put的区别

Java中ConcurrentHashMap putifAbsent方法的例子很多时候我们希望在元素不存在时插入元素,我们一般会像下面那样写代码synchronized(map){if (map.get(key) == null){return map.put(key, value);} else{return map.get(key);}}上面这段代码在HashMap和HashTable中是好用的,但在CHM中是有出错的风险的。这是因为CHM在put操作时并没有对整个Map加锁,所以一个线程正在put(k,v)的时候,另一个线程调用get(k)会得到null,这就会造成一个线程put的值会被另一个线程put的值所覆盖。当然,你可以将代码封装到synchronized代码块中,这样虽然线程安全了,但会使你的代码变成了单线程。CHM提供的putIfAbsent(key,value)方法原子性的实现了同样的功能,同时避免了上面的线程竞争的风险。
2023-07-16 15:55:071

为什么java.util.concurrent 包里没有并发的ArrayList实现

ArrayList 是非线程安全的,这点已经在文档中指出来了。如果你想要一个线程安全的就用 CopyOnWriteArrayList。它在修改时把数据复制一份再来修改,因此后续修改不影响正在跑迭代的其它线程。如果你需要一个同步的就可以直接 List synchronizedList = Collections.synchronizedList(new ArrayList());每种实现类都有它的优势和缺点,按我们的需要选择一个合适的就可以了。
2023-07-16 15:55:181

named user 和 concurrent user的区别

从概念上说 前者(web_concurrent_start)是语句的并发 后者(lr_rendezvous)是user的并发 这是两件完全完全不同的事情 没有什么可以比较的 仅仅只是都有“同时执行”的意思而已 详细来说
2023-07-16 15:55:251

请问“并发选收”/“并发优收”/“双发选收”用英文怎么说? 谢谢!

concurrent xuanshouconcurrent optimal chargedouble xuanshou网上找的 你的名词太难了 没办法
2023-07-16 15:55:332

java定时任务怎么实现

/*** 普通thread* 这是最常见的,创建一个thread,然后让它在while循环里一直运行着,* 通过sleep方法来达到定时任务的效果。这样可以快速简单的实现,代码如下:* @author GT**/public class Task1 {public static void main(String[] args) {// run in a secondfinal long timeInterval = 1000;Runnable runnable = new Runnable() {public void run() {while (true) {// ------- code for task to runSystem.out.println("Hello !!");// ------- ends heretry {Thread.sleep(timeInterval);} catch (InterruptedException e) {e.printStackTrace();}}}};Thread thread = new Thread(runnable);thread.start();}} [java] view plain copyimport java.util.Timer;import java.util.TimerTask;/**** 于第一种方式相比,优势 1>当启动和去取消任务时可以控制 2>第一次执行任务时可以指定你想要的delay时间** 在实现时,Timer类可以调度任务,TimerTask则是通过在run()方法里实现具体任务。 Timer实例可以调度多任务,它是线程安全的。* 当Timer的构造器被调用时,它创建了一个线程,这个线程可以用来调度任务。 下面是代码:** @author GT**/public class Task2 {public static void main(String[] args) {TimerTask task = new TimerTask() {@Overridepublic void run() {// task to run goes hereSystem.out.println("Hello !!!");}};Timer timer = new Timer();long delay = 0;long intevalPeriod = 1 * 1000;// schedules the task to be run in an intervaltimer.scheduleAtFixedRate(task, delay, intevalPeriod);} // end of main} [java] view plain copyimport java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/***** ScheduledExecutorService是从Java SE5的java.util.concurrent里,做为并发工具类被引进的,这是最理想的定时任务实现方式。* 相比于上两个方法,它有以下好处:* 1>相比于Timer的单线程,它是通过线程池的方式来执行任务的* 2>可以很灵活的去设定第一次执行任务delay时间* 3>提供了良好的约定,以便设定执行的时间间隔** 下面是实现代码,我们通过ScheduledExecutorService#scheduleAtFixedRate展示这个例子,通过代码里参数的控制,首次执行加了delay时间。*** @author GT**/public class Task3 {public static void main(String[] args) {Runnable runnable = new Runnable() {public void run() {// task to run goes hereSystem.out.println("Hello !!");}};ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间service.scheduleAtFixedRate(runnable, 10, 1, TimeUnit.SECONDS);}}
2023-07-16 15:55:511

如何在Python中编写并发程序

GIL在Python中,由于历史原因(GIL),使得Python中多线程的效果非常不理想.GIL使得任何时刻Python只能利用一个CPU核,并且它的调度算法简单粗暴:多线程中,让每个线程运行一段时间t,然后强行挂起该线程,继而去运行其他线程,如此周而复始,直到所有线程结束.这使得无法有效利用计算机系统中的"局部性",频繁的线程切换也对缓存不是很友好,造成资源的浪费.据说Python官方曾经实现了一个去除GIL的Python解释器,但是其效果还不如有GIL的解释器,遂放弃.后来Python官方推出了"利用多进程替代多线程"的方案,在Python3中也有concurrent.futures这样的包,让我们的程序编写可以做到"简单和性能兼得".多进程/多线程+Queue一般来说,在Python中编写并发程序的经验是:计算密集型任务使用多进程,IO密集型任务使用多进程或者多线程.另外,因为涉及到资源共享,所以需要同步锁等一系列麻烦的步骤,代码编写不直观.另外一种好的思路是利用多进程/多线程+Queue的方法,可以避免加锁这样麻烦低效的方式.现在在Python2中利用Queue+多进程的方法来处理一个IO密集型任务.假设现在需要下载多个网页内容并进行解析,单进程的方式效率很低,所以使用多进程/多线程势在必行.我们可以先初始化一个tasks队列,里面将要存储的是一系列dest_url,同时开启4个进程向tasks中取任务然后执行,处理结果存储在一个results队列中,最后对results中的结果进行解析.最后关闭两个队列.下面是一些主要的逻辑代码.# -*- coding:utf-8 -*-#IO密集型任务#多个进程同时下载多个网页#利用Queue+多进程#由于是IO密集型,所以同样可以利用threading模块import multiprocessingdef main(): tasks = multiprocessing.JoinableQueue() results = multiprocessing.Queue() cpu_count = multiprocessing.cpu_count() #进程数目==CPU核数目 create_process(tasks, results, cpu_count) #主进程马上创建一系列进程,但是由于阻塞队列tasks开始为空,副进程全部被阻塞 add_tasks(tasks) #开始往tasks中添加任务 parse(tasks, results) #最后主进程等待其他线程处理完成结果def create_process(tasks, results, cpu_count): for _ in range(cpu_count): p = multiprocessing.Process(target=_worker, args=(tasks, results)) #根据_worker创建对应的进程 p.daemon = True #让所有进程可以随主进程结束而结束 p.start() #启动def _worker(tasks, results): while True: #因为前面所有线程都设置了daemon=True,故不会无限循环 try: task = tasks.get() #如果tasks中没有任务,则阻塞 result = _download(task) results.put(result) #some exceptions do not handled finally: tasks.task_done()def add_tasks(tasks): for url in get_urls(): #get_urls() return a urls_list tasks.put(url)def parse(tasks, results): try: tasks.join() except KeyboardInterrupt as err: print "Tasks has been stopped!" print err while not results.empty(): _parse(results)if __name__ == "__main__": main()利用Python3中的concurrent.futures包在Python3中可以利用concurrent.futures包,编写更加简单易用的多线程/多进程代码.其使用感觉和Java的concurrent框架很相似(借鉴?)比如下面的简单代码示例def handler(): futures = set() with concurrent.futures.ProcessPoolExecutor(max_workers=cpu_count) as executor: for task in get_task(tasks): future = executor.submit(task) futures.add(future)def wait_for(futures): try: for future in concurrent.futures.as_completed(futures): err = futures.exception() if not err: result = future.result() else: raise err except KeyboardInterrupt as e: for future in futures: future.cancel() print "Task has been canceled!" print e return result总结要是一些大型Python项目也这般编写,那么效率也太低了.在Python中有许多已有的框架使用,使用它们起来更加高效.
2023-07-16 15:56:011