Questions tagged «concurrency»

在计算机科学中,并发是系统的属性,其中可以在重叠的时间段内执行多个计算。这些计算可以在同一芯片的多个内核上执行,也可以在同一处理器上抢占时间共享线程,或者在物理上分开的处理器上执行。

5
并发JUnit测试
我有一个大型的JUnit测试套件,出于两个原因,我想在其中同时运行所有测试: 利用多个内核来更快地运行整个测试套件 希望检测到由于非线程安全的全局对象而导致的一些错误 我知道这将迫使我重构一些代码以使其具有线程安全性,但是我认为这是一件好事:-) 使JUnit同时运行所有测试的最佳方法是什么?

5
什么是缓存命中和缓存未命中?为什么上下文切换会导致高速缓存未命中?
从第11章(性能和可伸缩性)以及JCIP书籍中名为上下文切换的部分开始: 切入新线程时,所需的数据不太可能位于本地处理器高速缓存中,因此上下文切换会导致大量高速缓存未命中,因此在首次调度线程时,它们的运行速度会稍微慢一些。 有人能以一种易于理解的方式解释高速缓存未命中的概念及其可能的对立面(高速缓存命中)吗? 为什么上下文切换会导致很多缓存丢失?

6
在使用ConcurrentMap的putIfAbsent之前是否应该检查地图是否包含Key
我一直在使用Java的ConcurrentMap作为可从多个线程使用的地图。putIfAbsent是一种很棒的方法,比使用标准映射操作更容易读/写。我有一些看起来像这样的代码: ConcurrentMap<String, Set<X>> map = new ConcurrentHashMap<String, Set<X>>(); // ... map.putIfAbsent(name, new HashSet<X>()); map.get(name).add(Y); 在可读性方面,这很棒,但是每次都需要创建一个新的HashSet,即使它已经在地图中了。我可以这样写: if (!map.containsKey(name)) { map.putIfAbsent(name, new HashSet<X>()); } map.get(name).add(Y); 进行此更改后,它将失去一些可读性,但无需每次都创建HashSet。在这种情况下哪个更好?我倾向于第一个,因为它更具可读性。第二个将表现更好,并且可能更正确。也许有比这两种方法更好的方法。 以这种方式使用putIfAbsent的最佳实践是什么?

5
Java 8:并行FOR循环
我听说Java 8提供了许多有关并发计算的实用程序。因此,我想知道并行化给定for循环的最简单方法是什么? public static void main(String[] args) { Set<Server> servers = getServers(); Map<String, String> serverData = new ConcurrentHashMap<>(); for (Server server : servers) { String serverId = server.getIdentifier(); String data = server.fetchData(); serverData.put(serverId, data); } }

5
条件与等待通知机制
与传统的等待通知机制相比,使用Condition接口/实现的优点是什么?在这里,我引用道格·李(Doug Lea)的评论: 条件将对象监视方法(wait,notify和notifyAll)分解为不同的对象,从而通过与任意Lock实现结合使用,从而使每个对象具有多个等待集。如果Lock替换了同步方法和语句的使用,而Condition替换了Object监视方法的使用。 我看到这是实现等待/通知机制的一种更面向对象的方式。但是,与前者相比有没有明显的优势?

6
Java的Fork / Join与ExecutorService-什么时候使用?
我刚读完这篇文章:与Java-7 ForkJoinPool相比,Java-5 ThreadPoolExecutor有什么优势?并认为答案不够直接。 您能用简单的语言和示例来说明Java 7的Fork-Join框架与较旧的解决方案之间的权衡吗? 我还阅读了关于Java技巧的Google排名第一的提示:何时使用javaworld.com上的ForkJoinPool与ExecutorService,但是本文没有回答when的标题问题,它主要讨论的是api的区别...

1
NSURLSession与Alamofire并发请求
我的测试应用程序遇到一些奇怪的行为。我有大约50个同时发送到同一服务器的GET请求。该服务器是资源有限的一小部分硬件上的嵌入式服务器。为了优化每个单个请求的性能,我将Alamofire.Manager如下配置一个实例: let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() configuration.HTTPMaximumConnectionsPerHost = 2 configuration.timeoutIntervalForRequest = 30 let manager = Alamofire.Manager(configuration: configuration) 当我发送请求时,manager.request(...)它们以2对的形式分派(按预期,通过Charles HTTP Proxy检查)。但是,很奇怪的是,由于第一个请求在30秒之内没有完成的所有请求,都会因为同时超时而被取消(即使尚未发送)。这是展示行为的例证: 这是预期的行为吗?如何确保请求在发送之前不会超时? 非常感谢!

6
SyncRoot模式的用途是什么?
我正在阅读一本描述SyncRoot模式的书。表明 void doThis() { lock(this){ ... } } void doThat() { lock(this){ ... } } 并与SyncRoot模式进行比较: object syncRoot = new object(); void doThis() { lock(syncRoot ){ ... } } void doThat() { lock(syncRoot){ ... } } 但是,我不太了解这里的区别。在这两种情况下,似乎两种方法一次只能由一个线程访问。 这本书描述了……因为实例的对象也可以用于外部的同步访问,并且您无法控制类本身的形式,因此可以使用SyncRoot模式。“实例的对象”? 谁能告诉我以上两种方法之间的区别?

4
为什么Java 5+中的volatile不能确保另一个线程的可见性?
根据: http://www.ibm.com/developerworks/library/j-jtp03304/ 在新的内存模型下,当线程A写入易失性变量V,而线程B从V读取时,现在保证了在写入V时A可见的任何变量值对B可见。 互联网上的许多地方都指出,以下代码永远不应显示“错误”: public class Test { volatile static private int a; static private int b; public static void main(String [] args) throws Exception { for (int i = 0; i < 100; i++) { new Thread() { @Override public void run() { int tt = b; // makes …

12
Java ReentrantReadWriteLocks-如何安全获取写锁?
我现在在代码中使用ReentrantReadWriteLock来同步树状结构的访问。这种结构很大,可以被许多线程同时读取,偶尔对其一部分进行修改,因此似乎很适合读写习惯。我知道对于这一特定类,不能将读取锁提升为写入锁,因此根据Javadocs,必须在获得写入锁之前释放读取锁。之前,我已经在非可重入上下文中成功使用了这种模式。 但是,我发现我无法可靠地获取写锁而不会永远阻塞。由于读锁是可重入的,而我实际上是这样使用的,因此简单的代码 lock.getReadLock().unlock(); lock.getWriteLock().lock() 如果我重新获得了readlock,则可以阻止。每次解锁请求只会减少保留计数,并且只有在保留计数达到零时才实际释放锁定。 编辑以澄清这一点,因为我认为我一开始解释得不太好-我知道此类中没有内置的锁升级,并且我必须简单地释放读取锁并获得写入锁。我的问题是/不管其他线程在做什么,如果重新获得了该调用,则调用getReadLock().unlock()实际上可能不会释放该线程的锁定,在这种情况下,getWriteLock().lock()由于此线程仍在读取状态,因此对它的调用将永远阻塞锁定并因此阻止自身。 例如,即使在没有其他线程访问锁的情况下运行单线程,此代码片段也永远不会到达println语句: final ReadWriteLock lock = new ReentrantReadWriteLock(); lock.getReadLock().lock(); // In real code we would go call other methods that end up calling back and // thus locking again lock.getReadLock().lock(); // Now we do some stuff and realise we need to write so try to …

1
Java中的内存防护有什么用?
在尝试了解如何实现SubmissionPublisher(Java SE 10中的源代码,OpenJDK | docs),在版本9中添加到Java SE的新类的实现之后,我偶然发现了一些VarHandle以前没有意识到的API调用: fullFence,acquireFence,releaseFence,loadLoadFence和storeStoreFence。 在进行了一些研究之后,尤其是关于内存屏障/栅栏的概念(我以前听说过,是的;但是从未使用过它们,因此对它们的语义非常陌生),我认为我对它们的用途有基本的了解。 。但是,由于我的问题可能是由错误的观念引起的,因此我想确保我一开始就正确: 内存障碍是关于读写操作的重新排序约束。 内存屏障可以分为两大类:单向和双向内存屏障,取决于它们是对读取还是写入或对这两者设置约束。 C ++支持多种内存屏障,但是这些屏障与所提供的屏障不匹配VarHandle。然而,一些在可用内存壁垒VarHandle提供排序的影响是兼容其相应的C ++内存屏障。 #fullFence 与...兼容 atomic_thread_fence(memory_order_seq_cst) #acquireFence 与...兼容 atomic_thread_fence(memory_order_acquire) #releaseFence 与...兼容 atomic_thread_fence(memory_order_release) #loadLoadFence并且#storeStoreFence没有兼容的C ++计数器部分 “ 兼容 ”一词在这里似乎非常重要,因为在细节上语义明显不同。例如,所有C ++障碍都是双向的,而Java障碍不是必需的。 大多数内存屏障也具有同步效果。这些特别取决于其他线程中使用的屏障类型和先前执行的屏障指令。由于障碍指令的全部含义是特定于硬件的,因此我将坚持使用更高级别的(C ++)障碍。在C ++中,例如,改变由之前的释放屏障指令是执行一个线程可见获取屏障指令。 我的假设正确吗?如果是这样,我的问题是: 可用的内存屏障是否VarHandle会引起任何类型的内存同步? 无论它们是否引起内存同步,重新排序约束在Java中可能有什么用?Java内存模型已经就可变字段,锁或VarHandle类似操作的顺序提供了一些非常有力的保证#compareAndSet。 如果您正在寻找一个示例:前面提到BufferedSubscription的SubmissionPublisher(内部链接为的内部类)在第1079行中建立了完整的围栏(功能growAndAdd;由于链接的网站不支持片段标识符,因此仅需使用CTRL + F )。但是,我不清楚它的用途。

2
Java指派执行程序由于某种原因失败时,停止执行程序服务
我需要某种服务,该服务将在1秒的间隔内同时运行1分钟1分钟。 如果其中一项任务失败,则我想停止该服务,并停止运行该服务的每个任务,并带有某种指示错误的指示器,否则,如果在一分钟后一切正常,则该服务将停止并指示所有指示器均正常运行。 例如,我有2个功能: Runnable task1 = ()->{ int num = Math.rand(1,100); if (num < 5){ throw new Exception("something went wrong with this task,terminate"); } } Runnable task2 = ()->{ int num = Math.rand(1,100) return num < 50; } ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); task1schedule = scheduledExecutorService.scheduleAtFixedRate(task1, 1, 60, TimeUnit.SECONDS); task2schedule = …

2
Kotlin协程“事前发生”的保证?
Kotlin协程是否提供任何“事前保证”? 例如,mutableVar在这种情况下,对(可能)其他线程的写入和后续读取之间是否存在“先于后继”保证: suspend fun doSomething() { var mutableVar = 0 withContext(Dispatchers.IO) { mutableVar = 1 } System.out.println("value: $mutableVar") } 编辑: 也许还有其他例子可以更好地阐明这个问题,因为它更具Kotlin风格(可变性除外)。这段代码是线程安全的吗: suspend fun doSomething() { var data = withContext(Dispatchers.IO) { Data(1) } System.out.println("value: ${data.data}") } private data class Data(var data: Int)

1
Haskell中平行的“任何”或“全部”
我现在遇到过一种模式,该模式需要通过在其上映射一些测试并查看是否有任何或所有元素通过来检查值列表。典型的解决方案是使用便捷的内置all和any。 问题是这些以串行方式进行评估。在许多情况下,这将是多快平行的过程被完整的评估,一旦任何线程发现一个“假”的all或“真”的any。我很确定不能使用Control.Parallel来实现短路行为,因为它需要进程间的通信,而且我对Control.Concurrent的理解还不够,无法实现此目的。 这是数学中的一种很常见的模式(例如Miller-Rabin Primality),所以我觉得有人可能已经为此提出了解决方案,但是出于明显的原因,谷歌搜索了“平行或/和//任何/全部在列表中” haskell”不会返回许多相关结果。

2
在程序员一级使用C ++ std :: atomic可以保证什么?
我已经听过并阅读了有关的几篇文章,演讲和stackoverflow问题std::atomic,并且我想确保自己已经很好地理解了。由于MESI(或派生的)高速缓存一致性协议,存储缓冲区,使队列无效等可能存在延迟,因此我仍然对高速缓存行的可见性感到困惑。 我读到x86具有更强的内存模型,并且如果缓存失效被延迟,x86可以还原启动的操作。但是我现在只对我作为独立于平台的C ++程序员应该承担的兴趣感兴趣。 [T1:线程1 T2:线程2 V1:共享原子变量] 我了解std :: atomic可以保证, (1)在变量上不发生数据争用(由于对缓存行的独占访问)。 (2)取决于我们使用哪种memory_order,它(在有障碍的情况下)保证发生顺序一致性(在障碍之前,之后或之后)。 (3)在T1上执行原子write(V1)之后,T2上的原子RMW(V1)将是连贯的(其缓存行将已用T1上的写入值进行更新)。 但是正如缓存一致性入门所述, 所有这些事情的含义是,默认情况下,加载可以获取过时的数据(如果相应的失效请求位于失效队列中) 那么,以下正确吗? (4)std::atomic不保证T2在T1上执行原子write(V)之后不会读取原子read(V)上的“陈旧”值。 问题(4)是否正确:如果无论延迟如何,在T1上进行原子写入都会使高速缓存行无效,那么当原子RMW操作而不是在原子读取上进行操作时,T2为什么要等待无效生效? 问题(4)是否错误:线程何时可以在执行过程中读取“过时”值并且“可见”? 非常感谢您的回答 更新1 所以看来我在(3)上错了。想象以下交织,初始V1 = 0: T1: W(1) T2: R(0) M(++) W(1) 即使在这种情况下,保证T2的RMW完全在W(1)之后发生,它仍然可以读取“过时的”值(我错了)。据此,atomic不能保证完全的缓存一致性,而只能保证顺序一致性。 更新2 (5)现在想象这个例子(x = y = 0并且是原子的): T1: x = 1; T2: y = 1; T3: if (x==1 && y==0) print("msg"); …

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.