Java并发控制多个锁
Java Concurrency control multiple locks
我有一个临界区,我需要控制只有具有给定属性值的线程才能同时进入。
例如:我有线程#1 处理产品,线程#2 也处理产品,线程#3 处理服务
现在:
T1先到,进入临界区,这样乘积就处理好了
T2想进入,但是因为有其他产品正在处理,所以必须等待
T3排在最后,可以进入,因为它需要处理一个服务(不是产品)
T1出去了,现在T2可以进来了
我觉得它看起来很简单,但我找不到符合要求的东西。
我的问题是,我怎样才能做到这一点?任何对此的任何信息来源的引用将不胜感激
非常感谢您
我认为您不能锁定值类型,但请尝试以下解决方法:将锁定对象放入数组中并从 ID 访问该数组。
类似于:
private Object[] locks = new Object[] {new Object(), new Object()};
private void yourMethod(int id)
{
synchronized(locks[id]) //or id - 1 if you want to stick to your 1 and 2
{
//do your things
}
}
希望对您有所帮助
如果你真的需要这个逻辑,可以这样实现:
private final Lock lock = new Lock();
public void process() {
boolean locked = false;
if (isProduct()) { // Depends on the current thread
lock.lock();
locked = true;
}
try {
// Do the work here
} finally {
if (locked) {
lock.unlock();
}
}
}
但是这个问题本身说明了一个糟糕的设计。只需创建方法 processProduct()
和 processService()
,创建第一个 synchronized
并从您的线程中调用您真正需要的方法。
我们对这个问题进行了不同的排序,具有高性能影响,使用普通锁,这在某些情况下会成为瓶颈。但我设法得到了一个解决方案,虽然没有经过测试。这由一个 Lock class 组成,它包含一个 Locks 池并根据 termId 将它们提供给线程。共享相同 termId 的所有线程将被提供相同的锁。这样我们就能得到所有按 termId 分组的线程,所有线程都排在不同的队列中。我设置了一个固定的锁池,虽然我认为它也可以是动态的,按需删除和添加锁。
如有任何反馈,我们将不胜感激
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
public class Lock {
private Lock() {}
private static class SingletonHolder {
/** ordered list. Locks with termId null must be at the end **/
public static final ArrayList<Lock> INSTANCES = new ArrayList<Lock>(){{
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
}};
public static synchronized Lock returnInstance(String termId){
ArrayList<Lock> sortedList = sortInstances();
for(Lock instance: sortedList){
if(termId.equals(instance.getTermId()))
return instance;
if(instance.getTermId()==null)
return instance;
}
return null;
}
public static ArrayList<Lock> sortInstances(){
ArrayList<Lock> sortedList=new ArrayList<Lock>();
for(Lock instance: INSTANCES){
if(instance.getTermId()==null)
sortedList.add(instance);
else
sortedList.add(0,instance);
}
return sortedList;
}
}
/**
* Use this method to get a reference to a singleton instance of
* {@link Lock}
*
* @return a singleton instance
*/
public static Lock getInstance(String termId) {
return SingletonHolder.returnInstance(termId);
}
private Semaphore lock = new Semaphore(1);
private String termId;
public void getLock(String termId) throws InterruptedException {
lock.acquire();
setTermId(termId);
}
public void releaseLock() {
lock.release();
setTermId(null);
}
public String getTermId() {
return termId;
}
public void setTermId(String termId) {
this.termId = termId;
}
}
这个怎么样:
private ConcurrentMap<Integer, Semaphore> semaphores = new ConcurrentHashMap<>();
public void enter(int id) {
Semaphore s = semaphores.computeIfAbsent(id, key -> new Semaphore(1));
try {
s.acquire();
// Critical section.
} catch (InterruptedException e) {
// Exception handling.
} finally {
s.release();
}
}
- 散列映射保证快速访问并且可以动态增长。此外,您还可以将对象用作键。
- 如果你在编译时知道ID的数量,你也可以使用不可修改或不可变的映射并预填充它。
- 信号量也可以调整:为不同的ID设置不同的许可数和公平性保证。
- 包装 class 可以提供额外的方法,例如通过
Semaphore#tryAcquire()
. 的非阻塞 tryEnter(int)
我有一个临界区,我需要控制只有具有给定属性值的线程才能同时进入。
例如:我有线程#1 处理产品,线程#2 也处理产品,线程#3 处理服务
现在:
T1先到,进入临界区,这样乘积就处理好了
T2想进入,但是因为有其他产品正在处理,所以必须等待
T3排在最后,可以进入,因为它需要处理一个服务(不是产品)
T1出去了,现在T2可以进来了
我觉得它看起来很简单,但我找不到符合要求的东西。 我的问题是,我怎样才能做到这一点?任何对此的任何信息来源的引用将不胜感激
非常感谢您
我认为您不能锁定值类型,但请尝试以下解决方法:将锁定对象放入数组中并从 ID 访问该数组。
类似于:
private Object[] locks = new Object[] {new Object(), new Object()};
private void yourMethod(int id)
{
synchronized(locks[id]) //or id - 1 if you want to stick to your 1 and 2
{
//do your things
}
}
希望对您有所帮助
如果你真的需要这个逻辑,可以这样实现:
private final Lock lock = new Lock();
public void process() {
boolean locked = false;
if (isProduct()) { // Depends on the current thread
lock.lock();
locked = true;
}
try {
// Do the work here
} finally {
if (locked) {
lock.unlock();
}
}
}
但是这个问题本身说明了一个糟糕的设计。只需创建方法 processProduct()
和 processService()
,创建第一个 synchronized
并从您的线程中调用您真正需要的方法。
我们对这个问题进行了不同的排序,具有高性能影响,使用普通锁,这在某些情况下会成为瓶颈。但我设法得到了一个解决方案,虽然没有经过测试。这由一个 Lock class 组成,它包含一个 Locks 池并根据 termId 将它们提供给线程。共享相同 termId 的所有线程将被提供相同的锁。这样我们就能得到所有按 termId 分组的线程,所有线程都排在不同的队列中。我设置了一个固定的锁池,虽然我认为它也可以是动态的,按需删除和添加锁。
如有任何反馈,我们将不胜感激
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
public class Lock {
private Lock() {}
private static class SingletonHolder {
/** ordered list. Locks with termId null must be at the end **/
public static final ArrayList<Lock> INSTANCES = new ArrayList<Lock>(){{
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
}};
public static synchronized Lock returnInstance(String termId){
ArrayList<Lock> sortedList = sortInstances();
for(Lock instance: sortedList){
if(termId.equals(instance.getTermId()))
return instance;
if(instance.getTermId()==null)
return instance;
}
return null;
}
public static ArrayList<Lock> sortInstances(){
ArrayList<Lock> sortedList=new ArrayList<Lock>();
for(Lock instance: INSTANCES){
if(instance.getTermId()==null)
sortedList.add(instance);
else
sortedList.add(0,instance);
}
return sortedList;
}
}
/**
* Use this method to get a reference to a singleton instance of
* {@link Lock}
*
* @return a singleton instance
*/
public static Lock getInstance(String termId) {
return SingletonHolder.returnInstance(termId);
}
private Semaphore lock = new Semaphore(1);
private String termId;
public void getLock(String termId) throws InterruptedException {
lock.acquire();
setTermId(termId);
}
public void releaseLock() {
lock.release();
setTermId(null);
}
public String getTermId() {
return termId;
}
public void setTermId(String termId) {
this.termId = termId;
}
}
这个怎么样:
private ConcurrentMap<Integer, Semaphore> semaphores = new ConcurrentHashMap<>();
public void enter(int id) {
Semaphore s = semaphores.computeIfAbsent(id, key -> new Semaphore(1));
try {
s.acquire();
// Critical section.
} catch (InterruptedException e) {
// Exception handling.
} finally {
s.release();
}
}
- 散列映射保证快速访问并且可以动态增长。此外,您还可以将对象用作键。
- 如果你在编译时知道ID的数量,你也可以使用不可修改或不可变的映射并预填充它。
- 信号量也可以调整:为不同的ID设置不同的许可数和公平性保证。
- 包装 class 可以提供额外的方法,例如通过
Semaphore#tryAcquire()
. 的非阻塞
tryEnter(int)