Java对重复非锁定条件信号的抽象

10 浏览
0 Comments

Java对重复非锁定条件信号的抽象

非常抱歉标题有些混乱。不太确定该如何表达,这可能是问题所在!

我正在寻找一个适用于涉及并发线程的情况的良好抽象。

我已经接近了,但还没完全掌握。稍微简化一下,我有两种类型的传感器输入在Android手机上收集 - 方向类型和WiFi扫描。

当两者都收集到足够的数据时,我希望触发一个事件来使用这些数据。然而,我希望这个过程继续进行N次。

起初,我只是在条件上使用while循环,例如:

startCollecting();
while (samplesCollected < X){
    // 等待
    while (directionCount < Y || scanCount < Z){}; 
    // 然后
    doSomeStuff();
    samplesCollected++; 
}
stopCollecting();

然而,我被SO告知这是一个性能不佳的方法,而且我确实在UI上遇到了一些锁定问题(尽管它在不同的线程上),所以我决定利用java.util.concurrent。

问题是我无法确定使用哪种抽象,可能是因为我经验不足。

  • 在ReentrantLock上使用Condition:

    条件的概念听起来很棒 - 但情况并不是我想要控制共享资源 - 我希望在处理第一批数据时后台继续进行数据收集 - 那么我在哪里调用锁定?如果我不锁定,它会抛出IllegalMonitorStateException异常。

  • CountdownLatch:

    看起来很理想 - 当收集线程有可用数据时,它们可以调用countDown(),当countDown被调用足够多次时,操作可以继续。但是countDown应该是一次性执行的,而我需要重复多次。

  • CyclicBarrier:

    CountdownLatch的文档建议在需要重复行为时使用CyclicBarrier - 但是CyclicBarrier的隐喻对于这种情况来说完全错误,并且我不知道如何在这种情况下使用它。

我在下面链接了一些相关的问题 - 对任何指导都将不胜感激。

Efficiency - use of Thread.yield in loop that waits for variable change

How to make a Java thread wait for another thread's output?

is there a 'block until condition becomes true' function in java?

A simple scenario using wait() and notify() in java

0
0 Comments

Java提供了一种重复非锁定条件信号的抽象方法,即使用并发队列(BlockingQueue类型的队列)。这种方法的出现是为了解决多线程环境下的数据同步问题。

具体的解决方法是将传感器读取的数据填充到并发队列中,而不是直接放入其他数据结构中。在循环中,使用take方法从队列中取出一条数据,然后根据数据的类型(方向或Wi-Fi)对应的计数器进行递增,并将数据放入某个位置(可能是一个本地的列表)。一旦收集到足够的数据,将收集到的数据传递给处理函数进行处理。

这种方法的原理是,当线程尝试从队列中取出数据而队列为空时,线程会进入休眠状态,而不是一直轮询计数器。这样可以有效地减少资源的占用。

可以看出,这种方法的关键在于使用BlockingQueue来处理等待的操作。处理任务只需要调用take方法获取数据,而具体的等待操作会被BlockingQueue处理。

这种方法的设计非常巧妙,能够有效地解决多线程环境下的数据同步问题。通过使用并发队列,可以简化线程间的数据交换和同步操作,提高系统的性能和可靠性。

0
0 Comments

Java中对于重复的非锁定条件信号的抽象化

在我们的代码中,我们有一个类似的实现。我们创建了一个实现了Runnable接口并能处理数据的内部类。我们在单个线程中不断读取数据,一旦数据的大小达到特定限制,就将该数据传递给内部类的实例,并将该内部类实例作为任务提交给ThreadPoolExecutor服务。这对我们来说非常有效。

+1 - 当你可以根据需要创建一个新的线程时,让样本处理线程保持空闲似乎没有任何优势

对,这也很有道理,并且在某种程度上避免了并发控制的问题。具体来说,你的意思是在onReceive()方法中放置数据大小的检查,并在单独的线程上触发数据收集吗?

没错,只是确保使用ThreadPoolExecutor触发线程 - 反复调用new Thread()会导致性能损失

我将这个回答标记为正确答案,因为它使用了较少的线程,并且似乎表现非常好。

0
0 Comments

Java抽象用于重复的非锁定条件信号的问题是由以下原因引起的:代码中存在忙等待,这通常是一个不好的事情。为了快速修复,您可以在内部while循环中添加Thread.sleep(25)(或等效的代码),这样可以解决死锁问题。

此外,变量samplesCollected,directionCount和scanCount应该标记为volatile或者使用AtomicLong(或AtomicInteger)。否则,您不能保证在另一个线程中对它们所做的更改会被看到。请阅读有关内存屏障和Java内存模型的相关内容,以了解其原因。

如果确保变量是线程安全的并添加Thread.sleep(...),则应该可以正常工作(不会锁定您的应用程序并且应该正确运行),尽管这不是一个理想的解决方法。

然而,这不是一个理想的解决方法。您可以通过让工作线程在每次递增后自行检查是否超过阈值来摆脱主线程。如果是,则它们可以启动一个线程(或在同一个线程中)执行您的后续聚合代码。类似地,如果达到某个最大阈值,您可以向所有线程发出停止收集的信号。但是,为了确保线程正确处理计数,您需要使用AtomicLong.incrementAndGet()(volatile将不起作用)。

对于简单的修复添加Sleep的方法,+1。如果没有Sleep,循环将使应用程序崩溃- CPU使用率飙升!

"添加Sleep的简单修复" - 我会称其为"添加不必要的延迟和性能差的简单修复"。Sleep()有其有效的用途,但不是有效线程间通信的替代方法。

0