.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() 可能会被唤醒;

这种歧义让我使用锁对象而不是使用同步方法......它们的实现有点复杂,但一旦(有点)理解它们就会感觉更直接。