Java - 死锁使用SWAP函数解决互斥

Java - Deadlock using SWAP function to solve mutual exclusion

我想用Swap函数解决互斥问题,但是程序死锁了,不知道为什么。好像是一个线程连续执行两次才会出现这个问题。

交换锁逻辑:

每个线程都使用一个 local 变量和一个 shared 变量。 线程首先锁定其 local 变量(例如假设 1 值)。 当线程 local 变量被解锁(例如假设 0 值)它可以执行临界区,如果线程 local 变量被锁定(例如假设1值)线程处于busy-waiting(忙等待测试局部变量解锁并调用swap函数)

交换函数将 local 变量设置为 shared 变量值并且 viceversa.The 交换函数必须是原子的。

当线程调用交换时,如果 "shared" 变量在交换后为 0(解锁),则 shared 变量为 1 且 local 到 0。 所以只有那个线程可以访问临界区,其他线程不能访问。

最后(不再有临界区)线程解锁 shared 变量。

主要

public class Mutex {

    public static void main(String []args){
        LockVar var = new LockVar(0);
        ThreadSwap th0 = new ThreadSwap(var);
        ThreadSwap th1 = new ThreadSwap(var);
        ThreadSwap th2 = new ThreadSwap(var);
        th0.start();
        th1.start();
        th2.start();
    }
}

线程Class (重点强调这类互斥量的逻辑)

class ThreadSwap extends Thread{

    private LockVar shared_var;

    public ThreadSwap(LockVar var){
    this.shared_var = var;
    }
    @Override
    public void run(){
        LockVar local = new LockVar(1);   
        while(true){
       ---> local.setVar(1);
       ---> while(local.getVar() == 1){Synch.SWAP(shared_var, local);}
            System.out.println("Thread " + getId() + " exec critical section."); 
            // Critical section
            System.out.println("Thread " + getId() + " is leaving critical section.");
       ---> shared_var.setVar(0);
        }
    }
}

交换功能

class Synch{
public static synchronized void SWAP(LockVar shared, LockVar local){
    int temp = shared.getVar();
    shared.setVar(local.getVar());
    local.setVar(temp);
}
...
}

共享变量Class

class LockVar{

    private volatile int var;

    public LockVar(int value){
        this.var = value;
    }
    public int getVar(){
        return this.var;
    }
    public void setVar(int value){
        this.var=value;
    }
}

想象一下这个场景:

  1. 第一个线程交换本地和 shared_var。现在 shared_var 是 1 而本地是 0.
  2. 由于 SWAP 上的同步是在 Synch class 上进行的,一旦第一个线程完成 SWAP,线程 2 就可以进入它。线程 2 使 temp = 1,此时监视器切换回线程 1。
  3. 线程 1 完成循环的第一次迭代,打印 exec 的消息并离开临界区并设置 shared_var = 0。监视器移至线程 2。
  4. 线程 2 继续执行 SWAP。它离开的地方。它执行 shared.setVar(local.getVar());(现在 shared_var == 1)和 local.setVar(temp);(记住步骤 2 中的温度为 1)。

死锁已经产生:shared_var为1,临界区内没有线程。这是因为 SWAP 不是原子的(监视器可以远离执行同步方法的线程,它只是不允许其他线程进入这种方法,也不允许其他方法在同一个锁上同步(class 在这种情况下静态方法的实例,在非静态方法的情况下是对象的实例))。

为了解决这个问题,您不应该允许 shared 在 SWAP 执行时更改,方法是找到一种使其成为原子的方法。一种可能性是摆脱 local 并使用 compareAndSet on an AtomicBoolean ,它现在将扮演 shared_var 的角色。

原子类型保证原子性和易变性(参见documentation)。这样,每个线程都应该获得对用于发信号的 AtomicBoolean 的引用(请原谅我松散的命名法),并使用 compareAndSet 以其他线程立即可见的方式自动更新变量的值:

import java.util.concurrent.atomic.AtomicBoolean;

public class Mutex {

  public static void main(String []args){
    AtomicBoolean isLocked = new AtomicBoolean(false);
    ThreadSwap th0 = new ThreadSwap(isLocked);
    ThreadSwap th1 = new ThreadSwap(isLocked);
    ThreadSwap th2 = new ThreadSwap(isLocked);
    th0.start();
    th1.start();
    th2.start();
  }
}

class ThreadSwap extends Thread {

  private AtomicBoolean shared_IsLocked;

  public ThreadSwap(AtomicBoolean var){
    this.shared_IsLocked = var;
  }

  @Override
  public void run(){
    while(true){
      // While the flag is true (locked), keep checking
      // If it is false (not locked), atomically change its value and keep going
      while(!shared_IsLocked.compareAndSet(false, true));
      System.out.println("Thread " + getId() + " exec critical section."); 
            // Critical section
      System.out.println("Thread " + getId() + " is leaving critical section.");
      shared_IsLocked.set(false);
    }
  }
}