Java多线程信号量

3
计数器变量不准确地反映了increment方法被调用的次数。为什么会这样,如何修复?(您不必编写代码,只需使用英语。)
import java.util.*;
import java.lang.*;
import java.io.*;


class Foopadoop
{
public static int counter = 0;
public static void main(String[] args) throws Exception {
    Runnable r = new Runnable() {
        public void run() {
            while(true){
                counter++;
            }
        }
    };
    Thread t1 = new Thread(r);
    Thread t2 = new Thread(r);
    t1.start();
    t2.start();
}
}

我添加了一个信号量,但我不确定是否做对了,或者我该使用锁。

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.concurrent.Semaphore;

class Foopadoop
{
public static int counter = 0;
Semaphore lock = new Semaphore(0);
public static void main(String[] args) throws Exception {
    Runnable r = new Runnable() {
        try{public void run() {
            while(true){
                counter++;
                lock.acquire();
            }
        }
       }finally{
         lock.release();
        }
    };
    Thread t1 = new Thread(r);
    Thread t2 = new Thread(r);
    t1.start();
    t2.start();
}
}
2个回答

4

这不是使用 Semaphore 的正确方式。

在访问共享资源之前,您需要获取它,并在访问结束后释放它:

while (true) {
  try {
    lock.acquire();
    counter++;
  } finally {
    lock.release();
  }
}

由于您首先需要 获取,因此您还需要至少1个许可证,否则就没有什么可以 获取的了:

static Semaphore lock = new Semaphore(1);

使用synchronized块比使用Semaphore更为简单:

while (true) {
  synchronized (Foopadoop.class) {
    counter++;
  }
}

或者使用AtomicInteger:

static AtomicInteger counter = new AtomicInteger();

// ...

while (true) {
  counter.getAndIncrement();
}

如果你要解释为什么这个东西不起作用,那会是这样吗——代码是否有误,因为线程多次初始化了该线程,从而导致计数器归零;但方法却运行了两次? - Kappa
1
不,这是错误的,因为您在获取信号量之前访问了共享资源。信号量的目的是强制对变量进行互斥访问。而且还因为您在释放之前多次获取。并且因为您正在尝试获取没有许可证的信号量。 - Andy Turner
我指的是原始问题,而不是我的代码版本。 - Kappa
在原始版本中,counter 只在类加载时初始化一次。问题在于,在线程之间更新 counter 的可见性不能保证;此外,其值也不能保证原子递增。 - Andy Turner
为了解决这个问题,如果我这样说会是一个有效的答案/解决方案吗:我们需要使用锁或信号量来阻塞其中一个线程,这样计数器就不会被初始化两次? - Kappa

0

此外,您可以在 while 循环中添加 Thread.sleep(ms) 方法,以便暂停当前线程一段时间,并开始执行其他线程。否则,当前线程可能会以自私的方式运行(自私线程)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接