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

时间:2015-04-07 04:57:24

标签: java synchronization deadlock swap mutual-exclusion

我想使用Swap函数解决互斥问题,但程序遇到死锁,我不知道为什么。当一个线程连续执行两次时,似乎会出现问题。

交换锁定逻辑:

每个线程都使用本地变量和共享变量。 线程首先锁定其本地变量(例如假设1值)。 当一个线程本地变量被解锁时(例如假设0值)它可以执行临界区,如果线程 local 变量被锁定(例如假定为1),则该线程为在忙等待(繁忙等待测试本地变量解锁并调用 swap 功能)

交换功能将本地变量设置为共享变量值,反之亦然。交换功能必须是ATOMIC。

当线程调用swap时,如果交换后“共享”变量为0(解锁),则 shared 变量为1, local 为0。 因此,只有该线程才能访问关键部分而不能访问其他部分。

最后(没有更多关键部分)线程解锁共享变量。

主要

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 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);
}
...
}

共享var类

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 个答案:

答案 0 :(得分:0)

想象一下这种情况:

  1. 第一个线程交换local和shared_var。现在shared_var为1,local为0。
  2. 由于SWAP上的同步是在Synch类上,所以只要第一个线程完成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中的temp为1)。
  5. 已经产生死锁:shared_var为1,并且临界区中没有线程。这是因为SWAP不是原子的(监视器可以远离执行同步方法的线程,它只是不允许其他线程进入这样的方法,也不允许其他方法在同一个锁上同步(在静态方法的情况下类) ,在非静态方法的情况下对象的实例))。

    为了解决这个问题,你不应该在执行SWAP时允许共享更改,方法是找到使其成为原子的方法。一种可能性是摆脱本地化,并在compareAndSet上使用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);
        }
      }
    }