Java 如何在操作时应用条件线程安全?

Java 如何在操作时应用条件线程安全?,java,collections,concurrency,thread-safety,critical-section,Java,Collections,Concurrency,Thread Safety,Critical Section,假设您有一个共享内存(列表),它将用作“评论部分”。 现在,考虑一下,在这些场景中,您总是有列表中的项目,并且希望您的系统以这种方式运行: Thread1从列表中获取某些项,而Thread2则希望将该项添加到列表中。允许这种情况(假设我将从开始处获取第一项,并在列表的末尾插入新项-同时!) Thread1想要获取一个项目,同时Thread2也想要获取一个项目。 这应该失败 谢谢一种可能性是将列表包装在一个类中,该类代理或重写get和add方法 这样,您就可以在add方法上使用显式的Lock,以便

假设您有一个共享内存(列表),它将用作“评论部分”。
现在,考虑一下,在这些场景中,您总是有列表中的项目,并且希望您的系统以这种方式运行:

  • Thread1从列表中获取某些项,而Thread2则希望将该项添加到列表中。允许这种情况(假设我将从开始处获取第一项,并在列表的末尾插入新项-同时!)

  • Thread1想要获取一个项目,同时Thread2也想要获取一个项目。 这应该失败


  • 谢谢

    一种可能性是将列表包装在一个类中,该类代理或重写get和add方法

    这样,您就可以在
    add
    方法上使用显式的
    Lock
    ,以便在任何给定时间只能添加一个线程

    例如,见:

    您可以通过扩展
    列表
    实现,覆盖
    添加
    获取
    方法(或所有相关方法),或者使用组合而不是继承,使用代理类将调用转发到列表,但是通过显式获取锁来装饰
    add
    get

    一个非常简单的例子如下:

    public class SharedMemory<K> {
    
    private final List<K> memoryList;
    private static final ReentrantLock lock = new ReentrantLock();
    
    public SharedMemory() {
        memoryList = new ArrayList<>();
    }
    
    public void storeItem(K item) {
        memoryList.add(item);
    }
    
    public K getItem(int pos){
        lock.lock();
        try{
            return memoryList.get(pos);
        } finally {
            lock.unlock();
        }
    }
    }
    
    公共类SharedMemory{
    私人最终名单记忆列表;
    私有静态最终ReentrantLock=新的ReentrantLock();
    公共共享内存(){
    memoryList=新的ArrayList();
    }
    公共无效存储项(K项){
    memoryList.add(项目);
    }
    公共K getItem(内部位置){
    lock.lock();
    试一试{
    返回memoryList.get(pos);
    }最后{
    lock.unlock();
    }
    }
    }
    
    一种可能性是将列表包装在一个类中,该类代理或重写get和add方法

    这样,您就可以在
    add
    方法上使用显式的
    Lock
    ,以便在任何给定时间只能添加一个线程

    例如,见:

    您可以通过扩展
    列表
    实现,覆盖
    添加
    获取
    方法(或所有相关方法),或者使用组合而不是继承,使用代理类将调用转发到列表,但是通过显式获取锁来装饰
    add
    get

    一个非常简单的例子如下:

    public class SharedMemory<K> {
    
    private final List<K> memoryList;
    private static final ReentrantLock lock = new ReentrantLock();
    
    public SharedMemory() {
        memoryList = new ArrayList<>();
    }
    
    public void storeItem(K item) {
        memoryList.add(item);
    }
    
    public K getItem(int pos){
        lock.lock();
        try{
            return memoryList.get(pos);
        } finally {
            lock.unlock();
        }
    }
    }
    
    公共类SharedMemory{
    私人最终名单记忆列表;
    私有静态最终ReentrantLock=新的ReentrantLock();
    公共共享内存(){
    memoryList=新的ArrayList();
    }
    公共无效存储项(K项){
    memoryList.add(项目);
    }
    公共K getItem(内部位置){
    lock.lock();
    试一试{
    返回memoryList.get(pos);
    }最后{
    lock.unlock();
    }
    }
    }
    
    这有什么意义?您是否在谈论不使用
    synchronized
    关键字或并发集合的情况下以某种方式执行此操作?您是否检查了
    CopyOnWriteArrayList
    功能?重点是根据情况1或2,类似于半并发。2应该是线程安全的,1不是,并且在相同的数据结构中实现它,我个人认为这样做是不可能的,但我只是想听听一些专家的意见advice@Quoi:我不熟悉,您认为它合适吗?您需要提供
    concurrenthashmap
    的细粒度锁定。这里有什么意义?您是否在谈论不使用
    synchronized
    关键字或并发集合的情况下以某种方式执行此操作?您是否检查了
    CopyOnWriteArrayList
    功能?重点是根据情况1或2,类似于半并发。2应该是线程安全的,1不是,并且在相同的数据结构中实现它,我个人认为这样做是不可能的,但我只是想听听一些专家的意见advice@Quoi:我不熟悉这个,你认为它合适吗?你需要提供
    concurrenthashmap
    的粒度锁定。它被认为是粒度锁定吗?我不确定你的意思。。。这里的锁定可以是您所需要的粒度,只需对其进行微调,以仅锁定需要“保护”的特定代码块即可。@JavaSa锁定粒度只是指您锁定的代码部分的大小。例如,如果您只应用了一个全局锁,那么它的粒度非常小。但是,如果每个方法只锁定一个或两个操作,这是非常精细的粒度。它被认为是粒度锁定吗?我不知道你的意思。。。这里的锁定可以是您所需要的粒度,只需对其进行微调,以仅锁定需要“保护”的特定代码块即可。@JavaSa锁定粒度只是指您锁定的代码部分的大小。例如,如果您只应用了一个全局锁,那么它的粒度非常小。但是,如果每个方法只锁定一个或两个操作,这是非常精细的粒度。