.wait() 在使用两个锁时失败
.wait() fails when using two locks
我需要创建一个带 2 个锁的线程。
代码在使用活套线程时运行良好,但由于任务简单,我改为使用线程。
public synchronized void setY(
int value
) {
if (value != 0) {
this.value = value;
yProvided = true;
} else {
YIsZero = true;
}
notifyAll();
}
public synchronized void provideEntity(EntityInterface entity) {
if (entity != null) {
this.entity = entity;
} else {
entityIsNull = true;
}
entityProvided = true;
notifyAll();
}
private synchronized void compare(
ComparatorSemaphore.ComparatorResult result
) {
Log.d(TAG, "compare: ");
while (!entityProvided) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
while (!yProvided) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
if (!entityIsNull) {
if (YIsZero) {
result.integerIsZero(entity);
} else {
if (value != entity.getContent()) {
result.onDifferent(entity, value);
} else {
result.onEqual(entity, value);
}
}
} else {
result.dataNotFound(value);
}
YIsZero = false;
value = 0;
yProvided = false;
}
我试过将两个锁都放在一个 wait() 中,但事实证明这种方式是迄今为止最安全的。
两种方法都是异步调用的,都是来自 2 个不同的 SQL 查询的响应。
日志
带LOGS的代码
while (!entityProvided) {
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW ENTITY");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, entity provided");
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
while (!yProvided) {
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW QUANTITY ");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, new quantity provided");
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
基本上 notifyAll() 正在唤醒线程,而 while() 循环迫使它开始锁定,因为它仍然锁定...
还有其他配置,例如 (!yProvided && !entityProvided) 有时会起作用,因此没用,还有其他配置,例如 ((!yProvided && !entityProvided)) 或 ((!yProvided) && (!entityProvided) ), 如果你问我为什么鸟枪调试是因为我无知
在最坏的情况下,获取的数据(EntityInterface 实体,我知道这是个坏名字,我会更改它)出于某种原因绕过所有空值检查。
代码仍然需要清理,我正在我的所有实体中实现一个接口以进行泛化,但我刚刚了解了泛型类型,我将在此代码中替换很多内容,但我确信那没有任何内容与锁的行为有关。
日志在 reset/reinstall 上的行为不同,并且在将日志放入查询观察器时它们的行为绝对正确?????这是什么波函数坍缩或某种东西 LMAO。
这是修改后的代码,它工作正常。
class CouplerRunnable<X, Y> implements Runnable {
private X x;
private Y y;
private volatile boolean yProvided = false;
private volatile boolean yIsNull = false;
private volatile boolean entityProvided = false;
private volatile boolean xIsNull = false;
public CouplerRunnable(JointResult<X, Y> result) {
mResult = result;
}
public synchronized void provideY(
Y y
) {
if (y != null) {
this.y = y;
} else {
yIsNull = true;
}
yProvided = true;
notifyAll();
}
public synchronized void provideX(X x) {
if (x != null) {
this.x = x;
} else {
xIsNull = true;
}
entityProvided = true;
notifyAll();
}
private synchronized void compare(
JointResult<X, Y> result
) {
Log.d(TAG, "compare: ");
while (!yProvided || !entityProvided) {
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW QUANTITY ");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, new quantity provided");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
result.onJointResponse(x, y);
}
yIsNull = false;
x = null;
y = null;
yProvided = false;
entityProvided = false;
xIsNull = false;
}
private JointResult<X, Y> mResult;
public interface JointResult<X, Y> {
void onJointResponse(X x, Y y);
}
public void run() {
Log.d(TAG, "run: ");
compare(
mResult
);
}
}
有些变量保留在那里以防万一,例如 private volatile boolean xIsNull = false;
或 private volatile boolean yIsNull = false;
,但目前没有使用它们。
代码按预期工作,,...也许有些行是多余的,例如末尾的空值或为字段变量布尔值分配了错误值...
界面写成@Functionalinterface
可能会更好
无论如何,我不知道编写多数据连接器(不仅仅是 2 个变量,而是许多变量)的代码有多少是个好主意,也许可以放置一个 System.currentTimeMillis() 信号量识别是否在非常短的时间内接收到传入数据,并在经过足够长的时间后将它们连接到 varArgs 响应中,这听起来不安全,但如果确定事情发生的顺序,它可能会很方便。
最后一点:
.wait() 方法不会永远 受 while 条件的限制。
每次通知();被调用(这是我不完全确定的部分),所有 .wait() 的(在 class(??) 内的 synchronized
方法内)都被唤醒,这意思是,日志告诉我确实正在调用通知,但是 while 循环是强制 wait() 重新检查条件并重新等待的循环。
在这个网站上的一个流行答案的某个地方,解释了锁等待和通知的功能,用户在 while 循环中放置了一个函数,在 try - catch 之后。
您必须非常小心,因为每当另一个线程调用 notify() 时 wait() 可能会被唤醒;
这种歧义让我使用锁对象而不是使用同步方法......它们的实现有点复杂,但一旦(有点)理解它们就会感觉更直接。
我需要创建一个带 2 个锁的线程。
代码在使用活套线程时运行良好,但由于任务简单,我改为使用线程。
public synchronized void setY(
int value
) {
if (value != 0) {
this.value = value;
yProvided = true;
} else {
YIsZero = true;
}
notifyAll();
}
public synchronized void provideEntity(EntityInterface entity) {
if (entity != null) {
this.entity = entity;
} else {
entityIsNull = true;
}
entityProvided = true;
notifyAll();
}
private synchronized void compare(
ComparatorSemaphore.ComparatorResult result
) {
Log.d(TAG, "compare: ");
while (!entityProvided) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
while (!yProvided) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
if (!entityIsNull) {
if (YIsZero) {
result.integerIsZero(entity);
} else {
if (value != entity.getContent()) {
result.onDifferent(entity, value);
} else {
result.onEqual(entity, value);
}
}
} else {
result.dataNotFound(value);
}
YIsZero = false;
value = 0;
yProvided = false;
}
我试过将两个锁都放在一个 wait() 中,但事实证明这种方式是迄今为止最安全的。
两种方法都是异步调用的,都是来自 2 个不同的 SQL 查询的响应。
日志
带LOGS的代码
while (!entityProvided) {
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW ENTITY");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, entity provided");
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
while (!yProvided) {
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW QUANTITY ");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, new quantity provided");
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
基本上 notifyAll() 正在唤醒线程,而 while() 循环迫使它开始锁定,因为它仍然锁定...
还有其他配置,例如 (!yProvided && !entityProvided) 有时会起作用,因此没用,还有其他配置,例如 ((!yProvided && !entityProvided)) 或 ((!yProvided) && (!entityProvided) ), 如果你问我为什么鸟枪调试是因为我无知
在最坏的情况下,获取的数据(EntityInterface 实体,我知道这是个坏名字,我会更改它)出于某种原因绕过所有空值检查。
代码仍然需要清理,我正在我的所有实体中实现一个接口以进行泛化,但我刚刚了解了泛型类型,我将在此代码中替换很多内容,但我确信那没有任何内容与锁的行为有关。
日志在 reset/reinstall 上的行为不同,并且在将日志放入查询观察器时它们的行为绝对正确?????这是什么波函数坍缩或某种东西 LMAO。
这是修改后的代码,它工作正常。
class CouplerRunnable<X, Y> implements Runnable {
private X x;
private Y y;
private volatile boolean yProvided = false;
private volatile boolean yIsNull = false;
private volatile boolean entityProvided = false;
private volatile boolean xIsNull = false;
public CouplerRunnable(JointResult<X, Y> result) {
mResult = result;
}
public synchronized void provideY(
Y y
) {
if (y != null) {
this.y = y;
} else {
yIsNull = true;
}
yProvided = true;
notifyAll();
}
public synchronized void provideX(X x) {
if (x != null) {
this.x = x;
} else {
xIsNull = true;
}
entityProvided = true;
notifyAll();
}
private synchronized void compare(
JointResult<X, Y> result
) {
Log.d(TAG, "compare: ");
while (!yProvided || !entityProvided) {
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW QUANTITY ");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, new quantity provided");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
result.onJointResponse(x, y);
}
yIsNull = false;
x = null;
y = null;
yProvided = false;
entityProvided = false;
xIsNull = false;
}
private JointResult<X, Y> mResult;
public interface JointResult<X, Y> {
void onJointResponse(X x, Y y);
}
public void run() {
Log.d(TAG, "run: ");
compare(
mResult
);
}
}
有些变量保留在那里以防万一,例如 private volatile boolean xIsNull = false;
或 private volatile boolean yIsNull = false;
,但目前没有使用它们。
代码按预期工作,,...也许有些行是多余的,例如末尾的空值或为字段变量布尔值分配了错误值...
界面写成@Functionalinterface
无论如何,我不知道编写多数据连接器(不仅仅是 2 个变量,而是许多变量)的代码有多少是个好主意,也许可以放置一个 System.currentTimeMillis() 信号量识别是否在非常短的时间内接收到传入数据,并在经过足够长的时间后将它们连接到 varArgs 响应中,这听起来不安全,但如果确定事情发生的顺序,它可能会很方便。
最后一点:
.wait() 方法不会永远 受 while 条件的限制。
每次通知();被调用(这是我不完全确定的部分),所有 .wait() 的(在 class(??) 内的 synchronized
方法内)都被唤醒,这意思是,日志告诉我确实正在调用通知,但是 while 循环是强制 wait() 重新检查条件并重新等待的循环。
在这个网站上的一个流行答案的某个地方,解释了锁等待和通知的功能,用户在 while 循环中放置了一个函数,在 try - catch 之后。
您必须非常小心,因为每当另一个线程调用 notify() 时 wait() 可能会被唤醒;
这种歧义让我使用锁对象而不是使用同步方法......它们的实现有点复杂,但一旦(有点)理解它们就会感觉更直接。