Java中锁定具有某些分区属性的对象(s)。

huangapple go评论52阅读模式
英文:

Java lock over object(s) with some partitioning property

问题

I have a class with some property (partition in the example below):

我有一个类,其中有一个属性(在下面的示例中是 partition)

and I have a function:

我有一个函数:

private void doSomething(Car car){

如果我有两个 Car 对象的实例,来自两个不同的线程调用函数 doSomething。同步块应该仅同步具有相同 "partition" 值的对象。当两个 Car 对象具有不同的分区键时,它们可以同时进入代码块。

如果我有两个 Car 对象的实例,来自两个不同的线程调用函数 doSomething。同步块应该仅同步具有相同 "partition" 值的对象。当两个 Car 对象具有不同的分区键时,它们可以同时进入代码块。

I was wondering how to write the "getLock" function. Should I use some map

我想知道如何编写 "getLock" 函数。我应该使用某个映射吗?

Map<String,Object> ?

Map<String, Object>?

Is there a better way to prevent 2 objects with the same property from entering the critical section?

有没有更好的方法来防止具有相同属性的两个对象进入关键部分?
英文:

I have a class with some property (partition in the example below)

class Car {
   public String partition;
   ....
}

and I have a function

private void doSomething(Car car){
   //  
     Object obj = getLock(car); // should write this function
     synchronized (obj){
          // do work here
     }

}

If I have 2 instances of the Car object

from 2 different threads the function doSomething is called. the synchronize block should sync only objects with the same "partition" value. When 2 car object have a different partition key they can both enter the block of code at the same time

I was wondering how to write the "getLock" function. Should I use some map

Map&lt;String,Object&gt; ? 

Is there a better way prevent 2 object with same property to enter the critical section?

答案1

得分: 1

是的,使用 Map<String, Object> 是实现 getLock 函数的适当方法,以实现基于 Car 对象的 partition 属性进行同步。该地图可用于存储每个唯一 partition 值的锁对象。

一个示例实现:

import java.util.HashMap;
import java.util.Map;

class Car {
    public String partition;
    // ...
}

public class CarManager {
    private Map<String, Object> lockMap = new HashMap<>();

    private Object getLock(Car car) {
        String partition = car.partition;
        synchronized (lockMap) {
            // Check if a lock object exists for the partition
            if (!lockMap.containsKey(partition)) {
                // If not, create a new lock object and store it in the map
                lockMap.put(partition, new Object());
            }

            // Return the lock object for the partition
            return lockMap.get(partition);
        }
    }

    private void doSomething(Car car) {
        Object obj = getLock(car);
        synchronized (obj) {
            // do work here
        }
    }
}
英文:

Yes, using a Map<String, Object> would be a suitable approach to implement the getLock function in order to achieve synchronization based on the partition property of the Car objects. The map can be used to store lock objects for each unique partition value.

an example implementation:

import java.util.HashMap;
import java.util.Map;

class Car {
    public String partition;
    // ...
}

public class CarManager {
    private Map&lt;String, Object&gt; lockMap = new HashMap&lt;&gt;();

    private Object getLock(Car car) {
        String partition = car.partition;
        synchronized (lockMap) {
            // Check if a lock object exists for the partition
            if (!lockMap.containsKey(partition)) {
                // If not, create a new lock object and store it in the map
                lockMap.put(partition, new Object());
            }

            // Return the lock object for the partition
            return lockMap.get(partition);
        }
    }

    private void doSomething(Car car) {
        Object obj = getLock(car);
        synchronized (obj) {
            // do work here
        }
    }
}

答案2

得分: 0

Sure, here's the translated part:

如果您确实想使用锁定,我建议查看分段锁的伪代码:

class CarManager{
    final Object[] lockStripe = new Object[Runtime.availableProcessors()*4];

     public CarManager(){
        for(int k=0;k<lockStripe.length;k++){
           lockStripe[k]=new Object();
        }
     }

     Object getLock(Car car){
	     int hash = car.partition.hashCode();
	     int lockIndex;
	
	       if (hash == Integer.MIN_VALUE) {
              lockIndex = 0;
           } else {
      	       lockIndex = abs(hash) % lockStripe.length;
           }
      
           return lockStripe[lockIndex];
     }

     public void doSomething(Car car){
	     synchronized(getLock(car)){
            ...
	     }
     }
}

这种方法将确保:

  1. 相同分区的汽车最终将使用相同的锁。
  2. 不同分区的汽车以较低的概率使用相同的锁。您可以通过更改lockStripe的长度来在内存利用和争用之间进行权衡。
  3. 不会获取全局锁
  4. 不会在不拥有的对象上进行锁定,如在分区对象上进行锁定。
  5. 由于保留不存在的对象的锁而导致的内存泄漏。
  6. 没有数据竞争
英文:

If you definitely want to use locking, I would have a look at a striped lock. Some pseudo-code:

class CarManager{
    final Object[] lockStripe = new Object[Runtime.availableProcessors()*4];

     public CarManager(){
        for(int k=0;k&lt;lockStripe.length;k++){
           lockStripe[k]=new Object();
        }
     }

     Object getLock(Car car){
	     int hash = car.partition.hashCode();
	     int lockIndex;
	
	       if (hash == Integer.MIN_VALUE) {
              lockIndex = 0;
           } else {
      	       lockIndex = abs(hash) % lockStripe.length;
           }
      
           return lockStripe[lockIndex];
     }

     public void doSomething(Car car){
	     synchronized(getLock(car)){
            ...
	     }
     }

This approach will ensure that:

  1. cars in the same partition will end up with the same lock.
  2. cars in different partitions have a low probability of ending up with the same lock. And you can make a trade-off between memory utilization and contention by changing the length of the lockStripe.
  3. no global lock is acquired
  4. no locks on objects you don't own like locking on the partition object.
  5. no memory leaks due to retaining locks of objects that do not exist any longer.
  6. no data races

huangapple
  • 本文由 发表于 2023年5月14日 16:13:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76246481.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定