gpt4 book ai didi

java - 了解 Java 线程干扰

转载 作者:行者123 更新时间:2023-11-30 08:32:44 25 4
gpt4 key购买 nike

我正在学习 Java,具有 Python 背景,并试图理解线程干扰,从本页中的代码和解释开始:http://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html

为了重现干扰,我有另一个启动三个线程的类,每个线程随机调用递增或递减 10 次。

我预计,有 3 个线程和 30 个递增或递减,有些会重叠,因此最终的 Counter值不等于 (# increments) - (# decrements) .

但每次我运行代码并分析结果输出时,我发现最终值等于 (# increments) - (# decrements) .虽然有可能在运行 5 次后,我不知何故没有受到任何干扰,但更有可能是我误解了干扰效果或无意中实现了避免干扰的代码。

这是我的代码:

// file: CounterThreads.java
public class CounterThreads {
private static class CounterThread implements Runnable {
private Counter c;

CounterThread(Counter c)
{
this.c = c;
}

public void run()
{
String threadName = Thread.currentThread().getName();
for (int i=0; i<10; i++) {
try {

if (((int)(Math.random() * 10) % 2) == 0) {
System.out.format("%s - Decrementing...\n", threadName);
c.decrement();
} else {
System.out.format("%s - Incrementing...\n", threadName);
c.increment();
}
System.out.format("%s - The internal counter is at %s\n", threadName, c.value());
Thread.sleep(1000);

} catch (InterruptedException e) {
System.out.format("Thread %s interrupted\n", threadName);
}
}
}
}

public static void main(String[] args)
{
Counter c = new Counter();
for (int i=0; i<3; i++) {
Thread t = new Thread(new CounterThread(c));
System.out.format("Starting Thread: %s\n", t.getName());
t.start();
}
}
}

文件Counter.java包含从上面的 oracle 文档中复制的代码,为方便起见在此处复制

// file: Counter.java
public class Counter {
private int c = 0;

void increment ()
{
c++;
}

void decrement()
{
c--;
}

int value()
{
return c;
}
}

最佳答案

要重现,您需要最大化概率同时递增和/或递减计数器(注意:这不是一件容易的事,因为递增/递减计数器是一个非常快速的操作),这不是您当前代码的情况,因为:

  1. 在递增/递减计数器之前,您不使用任何机制来同步线程。
  2. 您过于频繁地在错误的位置打印标准输出流中的消息,当您知道 PrintStream 是线程安全的并且使用内部锁来防止并发访问,这降低了同时增加和/或减少计数器的可能性。
  3. 您添加了一个无用的长 sleep ,这再次降低了您的计数器并发修改的可能性。
  4. 您没有使用尽可能多的线程。

因此,您的代码应该稍微重写以解决以前的问题。

要修复 #1,您可以使用 CyclicBarrier确保所有线程在继续之前到达相同的障碍点(位于递增/递减计数器之前)。

要解决 #2,我建议在增加/减少计数器后仅保留一条消息。

要修复 #3,我会简单地删除它,因为它无论如何也没用。

要修复 #4,我会使用 Runtime.getRuntime().availableProcessors() 作为要使用的线程数量,因为它将使用与本地计算机上一样多的处理器,这应该是足以完成此类任务。

所以最终的代码可以是:

反击

public class Counter {
private final CyclicBarrier barrier;
private int c;

public Counter(int threads) {
this.barrier = new CyclicBarrier(threads);
}

void await() throws BrokenBarrierException, InterruptedException {
barrier.await();
}
...
}

main 方法

public static void main(String[] args) {
int threads = Runtime.getRuntime().availableProcessors();
Counter c = new Counter(threads);
for (int i=0; i<threads; i++) {
...
}
}

run 方法的for 循环

try {
// Boolean used to know if the counter has been decremented or not
// It has been moved before the await to avoid doing anything before
// incrementing/decrementing the counter
boolean decrementing = (int)(Math.random() * 10) % 2 == 0;
// Wait until all threads reach this point
c.await();
if (decrementing) {
c.decrement();
} else {
c.increment();
}
// Print the message
System.out.format(
"%s - The internal counter is at %d %s\n",
threadName, c.value(), decrementing ? "Decrementing" : "Incrementing"
);

} catch (Exception e) {
System.out.format("Thread %s in error\n", threadName);
}

关于java - 了解 Java 线程干扰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39949526/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com