java - 结构如何正确通知其他线程有关事件的信息?

标签 java multithreading concurrency java.util.concurrent

我正在尝试编写一个线程安全结构来保留键值对并在一定时间延迟后自动删除它们。问题是,容器应该通知其他线程有关删除的信息。

我还尝试在同步块(synchronized block)中使用 notifyAll(),但问题仍然存在。

import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;


class Container <K extends Comparable<K>, V> {
    private ConcurrentHashMap <K, V> a;
    private final int delay = 2;
    private final Lock lock = new ReentrantLock();
    private final Condition removed = lock.newCondition();

    public Container() {
        a = new ConcurrentHashMap<>();
    }
    public synchronized void put(K k, V o) {
            lock.lock();
            a.put(k, o);
            new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(delay);


                    a.remove(k, o);
                    removed.signalAll();
                    lock.unlock();
                } catch (InterruptedException e){
                    e.printStackTrace();
                }

            }).start();

    }

    public  V get(int k)  {

        return a.get(k);
    }

    @Override
    public String toString() {
        return Stream.of(a)
        .filter(Objects::nonNull)
                .map(Object::toString)
                .collect(Collectors.joining(", ", "{", "}"));

    }
}

public class Main {

    public static void main(String [] args) throws InterruptedException {
        Container<Integer, Integer> c = new Container<>();
        c.put(0, 10);
        System.out.println(c);
        c.put(1, 11);
        c.put(2, 12);

        TimeUnit.SECONDS.sleep(3);
        System.out.println(c);

    }
}

程序以代码0结束并打印预期值:第一个元素和空结构。但无论哪种方式,我都得到了 IllegalMonitorStateException
任何想法,谢谢。

最佳答案

我们这里有一些事情需要注意:

  1. lock
  2. removed这是使用 lock 创建的条件

您的主线程获取 lock 上的锁在 put方法。 然而它永远不会释放锁;相反,它会创建一个新的 Thread调用 removed.signalAll() 。然而这个新线程没有持有锁lock这是需要这样做的。

我认为你需要做的是确保每个锁定 lock 的线程也解锁它并且每个线程调用 signalAll还有一个锁。

  public synchronized void put(K k, V o) {

    a.put(k, o);

    new Thread(() -> {
      try {
        TimeUnit.SECONDS.sleep(delay);

        lock.lock(); // get control over lock here
        a.remove(k, o);
        removed.signalAll();
        lock.unlock();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

    }).start();

  }

关于java - 结构如何正确通知其他线程有关事件的信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57140379/

相关文章:

java - 从列表和比较器 java 中删除

java - Mybatis添加更多参数时插入失败

c - 管理共享内存中的互斥量

objective-c - 如何在macOS的非主线程上发生事件循环?

c - 多次互斥锁定

java - java同步中条件变量和条件谓词的区别

java - 使用 JPA2 Criteria API 查询字符串子集

java - Firebase 数据库不向我显示图片

multithreading - 线程中的 Delphi 位图

c# - 此方法在哪个线程上运行? C#