Java 对计数器的线程安全读/写
我正在尝试使用线程安全方法使两个线程读/写计数器 我已经写了一些代码来测试这个,但是读取线程只是在最大值(1000)读取计数器 主要内容: 柜台:Java 对计数器的线程安全读/写,java,multithreading,thread-safety,atomic,Java,Multithreading,Thread Safety,Atomic,我正在尝试使用线程安全方法使两个线程读/写计数器 我已经写了一些代码来测试这个,但是读取线程只是在最大值(1000)读取计数器 主要内容: 柜台: public class Counter { private int count; public Counter() { count = 0; } public synchronized void increment() { count++; } public synchronized int getVal() { r
public class Counter {
private int count;
public Counter() {
count = 0;
}
public synchronized void increment() {
count++;
}
public synchronized int getVal() {
return count;
}
}
增量:
public class Increment extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Increment(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
myCounter.increment();
}
}
}
公共类增量扩展线程{
专用静态最终整数最大值=1000;
私人计数器;
公共增量(柜台c){
myCounter=c;
}
公开募捐{
对于(int i=0;i
阅读:
公共类读取扩展线程{
专用静态最终整数最大值=1000;
私人计数器;
公众阅读(c柜台){
myCounter=c;
}
公开募捐{
对于(int i=0;i
我是否最好使用原子整数来保存计数器的值,以便安全地递增计数器并获取值?如果您希望交错执行读取线程和递增线程的频率比自然的操作系统线程抢占更高,只要让每个线程放弃它们的锁(在相应的
run()
方法中调用.wait()
然后调用.notify()
或notifyAll()
:
[在Reader中]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
System.out.println(myCounter.getVal());
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void run(){
对于(int i=0;i
[增量]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
myCounter.increment();
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void run(){
对于(int i=0;i
将
MAX
常数增加到1_000_000_000
(10亿)会使踏板不时交错(在我的机器上,只需注视150和400_000迭代之间的少量打印输出即可进行交错).您的代码也很好。碰巧您的增量线程在读取线程有机会读取之前完成了所有增量。1000个增量几乎不需要任何时间。是的,但这是因为您当前的解决方案使用方法级同步。如果线程当前正在访问增量
然后另一个线程不会同时被阻止访问getVal
。另一个解决方案可能是将两个方法体包装在synchronized(this){}
blocks@JeroenSteenbeeke另一个线程将在任何synchronized
代码块上被阻止,因为该线程不是对象隐式锁的所有者。请原谅,Read只读取最大值这一事实不意味着线程是同步的吗?当Increment访问c时,没有其他线程可以访问它,所以t只有在增量写入完成后,他才能读取线程。尝试将最大值增加到一些实质性的值(1\u 000\u 000
),您应该会看到一些线程交错。计数到1000并不困难。如果希望读卡器在写入某个内容后立即读取,可以添加wait()
和notify()
(递增),是的,使用AtomicInteger是一个更好的解决方案。“不可能在同一个对象上交替调用两个同步方法。当一个线程为一个对象执行同步方法时,为同一个对象块调用同步方法的所有其他线程(暂停执行)直到第一个线程处理完对象为止。“@DavidSchwartzRead
和Increment
是独立的,不会暂停。每个主循环都会在没有其他主循环的情况下前进到最大值。您完全删除所有读取线程,增量将计为最大值。您可以使读取睡眠()对于某些情况,每次迭代将使其读取非连续增量。请(重新)测试。完全正确。尝试在Counter.increment()中添加延迟,您将看到在写入计数器时,没有人会读取。
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
System.out.println(myCounter.getVal());
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
myCounter.increment();
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}