使用java的经典有界缓冲问题变异的同步问题

时间:2011-04-05 12:34:38

标签: java multithreading thread-safety theory

我对经典的有界缓冲问题做了一个修改。

这是一个很大的不同,在我需要知道的线程安全的道路上有一个小的技术障碍(而不是无休止地测试可能永远不会发生的标准化)

我真的不认为我需要解释以下代码示例的评估情况

if(buffer1.BufferNotFull)
{
    buffer1.Lock();
    buffer1.AddValueAtIndex(value, index);
    buffer1.Unlock();
}

基本上我的buffer1有一个简单的条件变量(更新和全部),让我知道它是否已满,然后我获取一个锁,做魔术并释放锁。

但是我可以简单地假设评估条件“缓冲区不完整”不能与另一个线程交错,只是在我的缓冲区中写入LAST插槽吗?

(缓冲区实际上是一个值数组,-1表示空,不要问为什么^ _ ^)

简而言之:是评估

if(buffer1.BufferNotFull)

线程安全与正文代码获取锁

修改

这是我现在用于整个系统的系统。我希望它有助于展示我的设计。考虑到我将这个设计纯粹用于这些基本同步机制的学习目的。

访问缓冲区的线程的控制流程

读输入流(无需同步)

ATTEMPT:

  1. 从生产者线程写入操作 在buffer1请求锁定:
  2. 如果拒绝锁定,请继续请求 锁。
  3. 如果不满足条件变量, 等待
  4. 如果接受锁定,请执行写入 操作
  5. 解锁buffer1并通知其他人 等待线程。
  6. 如果输入流为空且缓冲区为1 死了,请求死亡 filterthread
  7. ATTEMPT:

    1. 从过滤器读取操作 buffer1上的线程请求锁定:
    2. 如果拒绝锁定,请继续请求锁定
    3. 如果接受锁定,请执行读取 操作(用-1替换值) 并将值存储在线程中 在应用过滤器之后。
    4. 如果不满足条件变量, 等待。
    5. 解锁buffer1并通知其他人 等待线程。
    6. 如果buffer1和buffer2为空并且 死亡请求存在,死亡。
    7. ATTEMPT:

      1. 从过滤器写入操作 buffer2上的线程请求锁定:
      2. 如果拒绝锁定,请继续请求锁定
      3. 如果接受锁定,请执行写入     操作(过滤后的     结果)。
      4. 如果不满足条件变量, 等待。
      5. 解锁buffer2并通知其他人 等待线程。
      6. 如果buffer1和buffer2为空并且 死亡请求存在,送死亡 请求消费者线程和模具。
      7. ATTEMPT:

        1. 从缓冲区读取缓冲区2的操作 消费者线索
        2. 如果拒绝锁定,请继续请求锁定
        3. 如果接受锁定,请执行读取     操作(用-1替换值)     并直接输出变量     到控制台上。
        4. 如果不满足条件变量, 等待。
        5. 解锁buffer2并通知其他人 等待线程。
        6. 如果buffer2为空并且死亡 请求存在,死亡。
        7. 控制各个线程操作的流程

          获取锁定 检查条件变量 如果是,则进行写/读操作 如果不是,请等待notfiy 解锁

          我将构建并测试实现的最后一部分并进行编辑,以查看接受的答案是否真的能让我获得结果,但这可能需要一些时间

1 个答案:

答案 0 :(得分:3)

通常,在上面的场景中,您必须首先获取锁定,然后测试条件是否为真:

buffer1.Lock();

try {

    while( !buffer1.BufferNotFull ) {

          buffer1.WaitOnConditionVariable();
    }

    buffer1.AddElement(...);

} finally {

    buffer1.Unlock();
}

操作的任何其他顺序都会带来“检查时间/使用时间”竞争条件的风险:考虑当前线程在使用{{1}检查状态后立即被抢占的情况但在抓住锁之前。如果新线程将新元素添加到缓冲区,则缓冲区的状态可能会再次变为“满”。当原始线程恢复时,它会在尝试添加自己的新元素时触发“缓冲区满”异常(或其他),即使它正确地检查(从它自己的角度来看)。

编辑条件变量将在“等待”操作期间实际进入休眠状态之前释放锁定。这是以原子方式完成的,即线程将在释放锁定时“在同一时刻”进入休眠状态。当某个其他线程通知该变量时,它会在调用“WaitOnConditionVariable”之后重新获取锁之前重新获取该锁。

从缓冲区中删除元素的代码可能如下所示:

BufferNotFull

或者,让它看起来像Java:

buffer1.Lock();

try {

    if( !buffer.IsEmpty ) { 

         ... remove element ...
         BufferNotFull = true;
         NotifyConditionVariable();
    }
} finally {
    buffer1.Unlock();
}

添加元素:

Object monitor = new Object();
boolean full = false;
boolean empty = true;

删除元素:

synchronized( monitor ) {
    while( full ) {
        monitor.wait();
    }

    ... add element ...
    ... maybe set full ...
    empty = false;
    monitor.notifyAll();
}