java避免死锁

java避免死锁,java,multithreading,Java,Multithreading,我们的应用程序(使用java)非常复杂,我得到了下面的示例代码,这些代码将在多线程环境中使用 现在的问题是,当我运行下面的代码(作为独立的主代码运行)时,我遇到了死锁 位置类别:- public class Location implements Runnable { private final int id; private final int[] dependentLocationIds; private final Lock lock = new Reentr

我们的应用程序(使用java)非常复杂,我得到了下面的示例代码,这些代码将在多线程环境中使用

现在的问题是,当我运行下面的代码(作为独立的主代码运行)时,我遇到了死锁

位置类别:-

public class Location implements Runnable {

    private final int id;

    private final int[] dependentLocationIds;

    private final Lock lock = new ReentrantLock();

    public Location(int id, int[] dependentLocationIds) {
        this.id = id;
        this.dependentLocationIds = dependentLocationIds;
    }

    public int getId() {
        return id;
    }

    public boolean blockLocation() {
        lock.lock();
        return true;
    }

    public boolean releaseLocation() {
        lock.unlock();
        return true;
    }

    public boolean occupy() {
        boolean occupationStatus = false;
        //order ids first
        Arrays.sort(dependentLocationIds);

        lock.lock();
        try {

            //below sleep temporarily added to track the progress slowly
            Thread.sleep(1000);

            //Check dependentLocations are NOT being modified concurrently
            for(int id : dependentLocationIds) {
                Location location = LocationHelper.getLocation(id);
                System.out.println(Thread.currentThread().getName()+": blocking required dependent location :"+id);
                location.blockLocation();
            }
            //the above blocked Locations will be released in leave()

            //complex business logic to check and then make occupationStatus to true
            occupationStatus = true;
            System.out.println(id + ": location occupied by:"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(!occupationStatus) {
                lock.unlock();
            }
           //if occupationStatus is true, the lock will be released in leave()
        }
        return occupationStatus;
    }

    public boolean leave() {
        boolean leaveStatus = false;
        //order ids first
        Arrays.sort(dependentLocationIds);
        try {
            //below sleep temporarily added to track the progress slowly
            Thread.sleep(1000);

            //complex business logic to check and then make leaveStatus to true
            leaveStatus = true;

            //now release dependent locations in reverse order
            for(int i=dependentLocationIds.length; i>0;i--) {
                Location location = LocationHelper.getLocation(id);
                System.out.println(Thread.currentThread().getName()+": releasing required dependent location :"+id);
                location.releaseLocation();
            }

            System.out.println(id + ": location released by "+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return leaveStatus;
    }

    public void run() {
        occupy();
        //some business logic goes here
        leave();
    }

    public static void main(String[] args) {
        List<Location> locations = LocationHelper.getLocations();

        for(Location location : locations) {
            //Each location runs in different threads here
            new Thread(location, "THREAD-"+location.getId()).start();
        }
    }
}
public class LocationHelper {

    private static final List<Location> locations = new ArrayList<>();

    static {
        int[] locationids1 = {2, 3, 4, 5};
        Location location1 = new Location(1, locationids1);
        locations.add(location1);

        int[] locationids2 = {1, 3, 4};
        Location location2 = new Location(2, locationids2);
        locations.add(location2);

        int[] locationids3 = {1, 2, 4};
        Location location3 = new Location(3, locationids3);
        locations.add(location3);

        int[] locationids4 = {3, 5};
        Location location4 = new Location(4, locationids4);
        locations.add(location4);

        int[] locationids5 = {1, 2, 3, 4};
        Location location5 = new Location(5, locationids5);
        locations.add(location5);
    }

    public static List<Location> getLocations() {
        return locations;
    }

    public static Location getLocation(int id) {
        Location required = null;

        for(Location location : locations) {
            if(location.getId() == id) {
                required = location;
            }
        }
        return required;
    }
}
公共类位置实现可运行{
私有最终int id;
私有final int[]dependentLocationId;
private final Lock=new ReentrantLock();
公共位置(int id,int[]DependentLocationId){
this.id=id;
this.DependentLocationId=DependentLocationId;
}
公共int getId(){
返回id;
}
公共布尔块位置(){
lock.lock();
返回true;
}
公共布尔releaseLocation(){
lock.unlock();
返回true;
}
公共布尔占用(){
布尔职业状态=false;
//先订购ID
Arrays.sort(dependentLocationId);
lock.lock();
试一试{
//下面临时添加睡眠以缓慢跟踪进度
睡眠(1000);
//没有同时修改Check DEpendentLocation
for(int-id:DependentLocationId){
Location Location=LocationHelper.getLocation(id);
System.out.println(Thread.currentThread().getName()+”:阻止所需的依赖位置:“+id”);
location.blockLocation();
}
//上述被阻止的位置将在leave()中释放
//检查复杂的业务逻辑,然后将occupationStatus设置为true
职业状态=真;
System.out.println(id+):被“+Thread.currentThread().getName()”占用的位置;
}捕捉(中断异常e){
e、 printStackTrace();
}最后{
如果(!职业状态){
lock.unlock();
}
//如果occupationStatus为true,将在leave()中释放锁
}
返回职业状态;
}
公共布尔休假(){
布尔状态=假;
//先订购ID
Arrays.sort(dependentLocationId);
试一试{
//下面临时添加睡眠以缓慢跟踪进度
睡眠(1000);
//检查复杂的业务逻辑,然后将leaveStatus设置为true
levestatus=true;
//现在按相反顺序释放依赖位置
对于(int i=DependentLocationId.length;i>0;i--){
Location Location=LocationHelper.getLocation(id);
System.out.println(Thread.currentThread().getName()+”:释放所需的依赖位置:“+id”);
location.releaseLocation();
}
System.out.println(id+):由“+Thread.currentThread().getName()”释放的位置;
}捕捉(中断异常e){
e、 printStackTrace();
}最后{
lock.unlock();
}
返回状态;
}
公开募捐{
占领();
//这里有一些商业逻辑
离开();
}
公共静态void main(字符串[]args){
List locations=LocationHelper.getLocations();
对于(位置:位置){
//每个位置在这里的不同线程中运行
新线程(位置,“Thread-”+location.getId()).start();
}
}
}
LocationHelper类:-

public class Location implements Runnable {

    private final int id;

    private final int[] dependentLocationIds;

    private final Lock lock = new ReentrantLock();

    public Location(int id, int[] dependentLocationIds) {
        this.id = id;
        this.dependentLocationIds = dependentLocationIds;
    }

    public int getId() {
        return id;
    }

    public boolean blockLocation() {
        lock.lock();
        return true;
    }

    public boolean releaseLocation() {
        lock.unlock();
        return true;
    }

    public boolean occupy() {
        boolean occupationStatus = false;
        //order ids first
        Arrays.sort(dependentLocationIds);

        lock.lock();
        try {

            //below sleep temporarily added to track the progress slowly
            Thread.sleep(1000);

            //Check dependentLocations are NOT being modified concurrently
            for(int id : dependentLocationIds) {
                Location location = LocationHelper.getLocation(id);
                System.out.println(Thread.currentThread().getName()+": blocking required dependent location :"+id);
                location.blockLocation();
            }
            //the above blocked Locations will be released in leave()

            //complex business logic to check and then make occupationStatus to true
            occupationStatus = true;
            System.out.println(id + ": location occupied by:"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(!occupationStatus) {
                lock.unlock();
            }
           //if occupationStatus is true, the lock will be released in leave()
        }
        return occupationStatus;
    }

    public boolean leave() {
        boolean leaveStatus = false;
        //order ids first
        Arrays.sort(dependentLocationIds);
        try {
            //below sleep temporarily added to track the progress slowly
            Thread.sleep(1000);

            //complex business logic to check and then make leaveStatus to true
            leaveStatus = true;

            //now release dependent locations in reverse order
            for(int i=dependentLocationIds.length; i>0;i--) {
                Location location = LocationHelper.getLocation(id);
                System.out.println(Thread.currentThread().getName()+": releasing required dependent location :"+id);
                location.releaseLocation();
            }

            System.out.println(id + ": location released by "+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return leaveStatus;
    }

    public void run() {
        occupy();
        //some business logic goes here
        leave();
    }

    public static void main(String[] args) {
        List<Location> locations = LocationHelper.getLocations();

        for(Location location : locations) {
            //Each location runs in different threads here
            new Thread(location, "THREAD-"+location.getId()).start();
        }
    }
}
public class LocationHelper {

    private static final List<Location> locations = new ArrayList<>();

    static {
        int[] locationids1 = {2, 3, 4, 5};
        Location location1 = new Location(1, locationids1);
        locations.add(location1);

        int[] locationids2 = {1, 3, 4};
        Location location2 = new Location(2, locationids2);
        locations.add(location2);

        int[] locationids3 = {1, 2, 4};
        Location location3 = new Location(3, locationids3);
        locations.add(location3);

        int[] locationids4 = {3, 5};
        Location location4 = new Location(4, locationids4);
        locations.add(location4);

        int[] locationids5 = {1, 2, 3, 4};
        Location location5 = new Location(5, locationids5);
        locations.add(location5);
    }

    public static List<Location> getLocations() {
        return locations;
    }

    public static Location getLocation(int id) {
        Location required = null;

        for(Location location : locations) {
            if(location.getId() == id) {
                required = location;
            }
        }
        return required;
    }
}
公共类LocationHelper{
私有静态最终列表位置=新ArrayList();
静止的{
int[]locationids1={2,3,4,5};
位置location1=新位置(1,位置IDS1);
位置。添加(位置1);
int[]locationids2={1,3,4};
位置location2=新位置(2,位置ids2);
位置。添加(位置2);
int[]locationids3={1,2,4};
位置location3=新位置(3,位置IDS3);
位置。添加(位置3);
int[]locationids4={3,5};
位置location4=新位置(4,位置IDS4);
位置。添加(位置4);
int[]locationids5={1,2,3,4};
位置location5=新位置(5,位置IDS5);
位置。添加(位置5);
}
公共静态列表getLocations(){
返回地点;
}
公共静态位置getLocation(int-id){
所需位置=空;
对于(位置:位置){
if(location.getId()==id){
所需=位置;
}
}
要求归还;
}
}
核心要求是当我更新特定的“位置”时 对象,不应允许任何依赖的“位置”对象 改变因此,我也尝试锁定依赖对象,这就是复杂性产生的原因

我尝试根据“位置id”(唯一)对位置对象进行排序,然后锁定位置对象,以避免死锁,但没有运气。

你能帮我修改一下代码以避免死锁吗

如何重构“Location”类以消除上述复杂性?
或者,“Location”类还有其他更好的设计选项(使用并发api)来简化上述逻辑吗?请帮助。

订购的想法看起来不错,订购必须解决解除死锁问题。如果你总是以同样的顺序获得锁,你就会安全

然而,我注意到您只订购直系亲属。在开始锁定之前,您应该递归地对所有依赖项进行排序。并且自己的实例也应该将自己放入要排序的列表中

这样,您将安全地锁定每个位置的所有“依赖关系树”

如需说明,请仅查看以下示例
public boolean occupy() {
    boolean occupationStatus = false;
    masterLock.lock();
    try{
        //order ids first
        Arrays.sort(dependentLocationIds);

        if(lock.tryLock()){
            //handle already blocked
        }
        try {
            //bunch of stuff
        } finally {
            if(!occupationStatus) {
                lock.unlock();
            }
        }
    }finally{
        masterLock.unlock();
    }
    return occupationStatus;
}
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Location
    implements Runnable
{

  private final int id;

  private final List<Integer> dependentLocationIds;

  private final Lock lock = new ReentrantLock();

  private boolean isUnlocked = true;

  public Location(int id, List<Integer> dependentLocationIds)
  {
    this.id = id;
    this.dependentLocationIds = dependentLocationIds;
    Collections.sort(dependentLocationIds);
  }

  public int getId()
  {
    return id;
  }

  public List<Integer> getDependentLocationIds()
  {
    return dependentLocationIds;
  }

  public boolean isUnlocked()
  {
    return isUnlocked;
  }

  public boolean blockLocation()
  {
    lock.lock();
    isUnlocked = false;
    System.out.printf("Location: %d occupied by: %s\n", this.getId(),
        Thread.currentThread().getName());
    return isUnlocked;
  }

  public boolean releaseLocation()
  {
    lock.unlock();
    isUnlocked = true;
    System.out.printf("Location: %d released by: %s\n", this.getId(),
        Thread.currentThread().getName());
    return isUnlocked;
  }

  public void occupy()
  {
    while (!LocationHelper.acquireLocks(this))
    {
      try
      {
        System.out.printf("Location: %d sleeping during occupy on: %s\n",
            this.getId(), Thread.currentThread().getName());
        Thread.sleep(1500);
      }
      catch (InterruptedException e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    try
    {
      // below sleep added to track the progress slowly
      Thread.sleep(1000);

      System.out.printf("Location: %d doing something on: %s\n", this.getId(),
          Thread.currentThread().getName());
    }
    catch (InterruptedException e)
    {
      e.printStackTrace();
      LocationHelper.releaseLocks(this);
    }
  }

  public void leave()
  {
    try
    {
      // below sleep added to track the progress slowly
      Thread.sleep(1000);

      System.out.printf("Location: %d is attempting to leave on: %s\n",
          this.getId(), Thread.currentThread().getName());
      LocationHelper.releaseLocks(this);
    }
    catch (InterruptedException e)
    {
      e.printStackTrace();
    }
    finally
    {
      LocationHelper.releaseLocks(this);
    }
  }

  public void run()
  {
    occupy();
    leave();
  }

  public static void main(String[] args)
  {
    List<Location> locations = LocationHelper.getLocations();

    for (Location location : locations)
    {
      // Each location runs in different threads here
      new Thread(location, "THREAD-" + location.getId()).start();
    }
  }
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LocationHelper
{
  private static List<Location> holdsLocks = new ArrayList<Location>();

  private static final List<Location> locations = new ArrayList<>();

  private static int printLocks = 0;

  static
  {
    locations.add(new Location(1, Arrays.asList(1, 2, 3, 4, 5)));
    locations.add(new Location(2, Arrays.asList(1, 2, 3, 4)));
    locations.add(new Location(3, Arrays.asList(1, 2, 3, 4)));
    locations.add(new Location(4, Arrays.asList(3, 4, 5)));
    locations.add(new Location(5, Arrays.asList(1, 2, 3, 4, 5)));
  }

  public static List<Location> getLocations()
  {
    return locations;
  }

  public static Location getLocation(int id)
  {
    return locations.stream().filter(l -> l.getId() == id).findFirst()
        .orElse(null);
  }

  public static synchronized boolean acquireLocks(Location location)
  {
    if (printLocks % 5 == 0)
    {
      locations.stream()
          .forEach(l -> System.out.printf("Location: %d status: %s\n",
              l.getId(), String.valueOf(l.isUnlocked())));
    }
    List<Location> required = location.getDependentLocationIds().stream()
        .map(LocationHelper::getLocation).collect(Collectors.toList());
    // If not available fail to lock.
    if (required.stream().filter(l -> !l.isUnlocked()).count() > 0L)
    {
      return false;
    }
    else
    {
      try
      {
        required.stream().forEach(Location::blockLocation);
        holdsLocks.add(location);
        return true;
      }
      catch (Exception e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
        required.stream().forEach(Location::releaseLocation);
        return false;
      }
    }
  }

  public static boolean releaseLocks(Location location)
  {
    if (!holdsLocks.contains(location))
    {
      return false;
    }
    else
    {
      List<Location> required = location.getDependentLocationIds().stream()
          .map(LocationHelper::getLocation).collect(Collectors.toList());

      try
      {
        required.stream().forEach(Location::releaseLocation);
        holdsLocks.remove(location);
        return true;
      }
      catch (Exception e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return false;
      }
    }
  }
}