s3r*_*ius 10 java concurrency multithreading synchronized
这不是我的功课,这是给大学学生的一项任务.出于个人兴趣,我对解决方案感兴趣.
任务是创建一个包含整数的类(Calc).这两个方法add和mul应该添加或乘以这个整数.
同时设置两个线程.一个线程应该调用c.add(3)十次,另一个应该调用c.mul(3)十次(当然在同一个Calc对象上).
Calc类应确保操作交替完成(add,mul,add,mul,add,mul,..).
我没有经常处理与并发相关的问题 - 更不用说Java了.我已经为Calc提出了以下实现:
class Calc{
private int sum = 0;
//Is volatile actually needed? Or is bool atomic by default? Or it's read operation, at least.
private volatile bool b = true;
public void add(int i){
while(!b){}
synchronized(this){
sum += i;
b = true;
}
}
public void mul(int i){
while(b){}
synchronized(this){
sum *= i;
b = false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道我是否走在正确的轨道上.对于while(b)部分来说,肯定有一种更优雅的方式.我想听听你们这些人的想法.
PS:不得更改方法的签名.除此之外,我不受限制.
Jiv*_*ngs 11
尝试使用Lock界面:
class Calc {
private int sum = 0;
final Lock lock = new ReentrantLock();
final Condition addition = lock.newCondition();
final Condition multiplication = lock.newCondition();
public void add(int i){
lock.lock();
try {
if(sum != 0) {
multiplication.await();
}
sum += i;
addition.signal();
}
finally {
lock.unlock();
}
}
public void mul(int i){
lock.lock();
try {
addition.await();
sum *= i;
multiplication.signal();
} finally {
lock.unlock();
}
}
}
Run Code Online (Sandbox Code Playgroud)
锁定就像你的同步块一样.但是这些方法将等待.await()另一个线程是否保持调用lockuntil .signal().
JB *_*zet 10
你所做的是一个繁忙的循环:你正在运行一个只在变量发生变化时停止的循环.这是一个糟糕的技术,因为它使CPU非常繁忙,而不是简单地使线程等待,直到更改标志.
我会使用两个信号量:一个用于multiply,一个用于add.add必须addSemaphore在添加之前获得,并multiplySemaphore在完成时释放许可,反之亦然.
private Semaphore addSemaphore = new Semaphore(1);
private Semaphore multiplySemaphore = new Semaphore(0);
public void add(int i) {
try {
addSemaphore.acquire();
sum += i;
multiplySemaphore.release();
}
catch (InterrupedException e) {
Thread.currentThread().interrupt();
}
}
public void mul(int i) {
try {
multiplySemaphore.acquire();
sum *= i;
addSemaphore.release();
}
catch (InterrupedException e) {
Thread.currentThread().interrupt();
}
}
Run Code Online (Sandbox Code Playgroud)
正如其他人所说,volatile你的解决方案是必需的.此外,您的解决方案旋转等待,这可能会浪费相当多的CPU周期.也就是说,就有关的正确性而言,我看不出任何问题.
我个人会用一对信号量来实现它:
private final Semaphore semAdd = new Semaphore(1);
private final Semaphore semMul = new Semaphore(0);
private int sum = 0;
public void add(int i) throws InterruptedException {
semAdd.acquire();
sum += i;
semMul.release();
}
public void mul(int i) throws InterruptedException {
semMul.acquire();
sum *= i;
semAdd.release();
}
Run Code Online (Sandbox Code Playgroud)
需要 volatile,否则优化器可能会将循环优化为if(b)while(true){}
但你可以用waitand来做到这一点notify
public void add(int i){
synchronized(this){
while(!b){try{wait();}catch(InterruptedException e){}}//swallowing is not recommended log or reset the flag
sum += i;
b = true;
notify();
}
}
public void mul(int i){
synchronized(this){
while(b){try{wait();}catch(InterruptedException e){}}
sum *= i;
b = false;
notify();
}
}
Run Code Online (Sandbox Code Playgroud)
但是在这种情况下(b 在同步块内检查)不需要 volatile