and*_*ert 3 java synchronization
虽然SO和其他地方有很多关于之前发生过的关系的帖子,但我很难找到对我的问题的确切答案.
考虑两个Java线程:
最初,flag == false和data == 0
T1
data = 42;
synchronized(m) {
flag = true;
}
Run Code Online (Sandbox Code Playgroud)
T2
boolean f;
synchronized(m) {
f = flag;
}
if (f) {
int x = data;
}
Run Code Online (Sandbox Code Playgroud)
根据上面的代码,我相信f可以分配价值,true或者false没有保证.它是否正确?
现在,如果将两个synchronized语句更改为synchronized(flag),我认为指令flag = true将始终在指令之前发生f = flag,因此f将始终为该指令赋值true.它是否正确?
不,同步不保证Thread首先到达那里.仅保证一次Thread不能访问同步块.
把一个synchronized街区想象成一个带门锁的房间.我们不知道谁会首先到达门口,但一旦他们这样做,他们就会进门并锁上门.
其他人必须等到房间里的人准备离开并解锁门.一旦发生这种情况,每个人都会再次参加比赛.
这一切都取决于你Thread关闭的顺序.但即使这样,也没有任何保证,因为JVM可能会随机暂停Threads和Threads yield.在类比中 - 领先到门的人可能会在香蕉皮上绊倒.不太可能,但总是可能的.
如果你想要保证,那么你需要wait/ notify- 以便读取线程检查flag,如果是false,则在循环中挂起它自己.
写入线程然后设置flag并通知锁定监视器唤醒读取线程.
下面是使用的例子Lock,并Condition从Java API 5.我不是说你必须要使用优先于synchronized和wait/ notify-这只是一个例子,我已经躺在附近,我适应.
的Reader获取lock,然后检查ready标志在一个循环.如果标志是false其awaitS ON的状态.这原子地释放lock并暂停Thread.
的Writer同时获取lock和设置data和ready标志.然后它调用signalAll并释放lock.
这会唤醒Reader然后读取readyas true并继续执行print语句.
输出将始终为42(从不-1).
public class App {
static volatile boolean ready = false;
static volatile int data = -1;
private static class Reader implements Runnable {
private final Lock lock;
private final Condition condition;
public Reader(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
try {
while (!ready) {
try {
condition.await();
} catch (InterruptedException ex) {
//oh well
}
}
System.out.println(data);
} finally {
lock.unlock();
}
}
}
private static class Writer implements Runnable {
private final Lock lock;
private final Condition condition;
public Writer(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
try {
data = 42;
ready = true;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
executorService.execute(new Reader(lock, condition));
executorService.execute(new Writer(lock, condition));
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
}
}
Run Code Online (Sandbox Code Playgroud)