Java中的并发管理

Java中的并发管理,java,concurrency,queue,Java,Concurrency,Queue,我创建了一个简单的搜索引擎: public String search(Map<String, Object> params) { String result = /*search*/; return result; } 这是工作真的很好,但再次有一个小问题 测试: public static void main(String[] args) { String id = "1"; ProcessSession session = ProcessMan

我创建了一个简单的搜索引擎:

public String search(Map<String, Object> params) {
    String result = /*search*/;
    return result;
}
这是工作真的很好,但再次有一个小问题

测试

public static void main(String[] args) {
    String id = "1";
    ProcessSession session = ProcessManager.openSession(id);
    //...
    ExecutorService service = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        service.submit(() -> session.search("keyword"));
    }
}
new search
waiting
waiting
new search
waiting
waiting
waiting
waiting
waiting
waiting
编辑:

public final class Locker<K, V> {

    private final Object o = new Object();
    private final K key;
    private V value;

    public Locker(K key) {
        this.key = key;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }

    public void lock() {
        synchronized (o) {
            try {
                o.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void lock(long timeout) {
        synchronized (o) {
            try {
                o.wait(timeout);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void unlock() {
        synchronized (o) {
            o.notify();
        }
    }

}
public期末班储物柜{
私有最终对象o=新对象();
私钥;
私人价值;
公用储物柜(K钥匙){
this.key=key;
}
公共K getKey(){
返回键;
}
public V getValue(){
返回值;
}
公共无效设置值(V值){
这个值=值;
}
公共无效锁(){
同步(o){
试一试{
o、 等待();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公共无效锁(长超时){
同步(o){
试一试{
o、 等待(超时);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公开作废解锁(){
同步(o){
o、 通知();
}
}
}
这里出了什么问题?有人能提出更好的解决方案吗


谢谢。

使用concurrent collections的东西只会在细粒度级别进行锁定,因此您不会得到太多好处

我会设计一个有点不同的搜索。这里的想法应该是设计
search
方法,使它的两个调用相互排斥。我想到的一个方法是在这里使用一种消费模式

  • Search
    方法为对其进行的每个调用创建一个工作线程,该工作线程由无限执行器服务执行
  • 另一种方法是让工人排队
    search
    方法创建工人并将他们添加到队列中,另一个executor服务不断从队列中挑选工人来执行并返回结果

在所有情况下,其想法都是使搜索操作的实例相互排斥。如果可以,也可以缓存这些东西

您可以使用标志来实现更好的性能,而不是使用锁和同步块

当第一次搜索发生时,在地图中设置一个标记“进行中”,并将搜索关键字作为键。 因此,当重复搜索出现时,您可以查找此映射并决定等待或进行长时间轮询以获取第一次搜索的结果

搜索完成后,尽可能缓存结果并删除标志


您可以使用套接字编程,同时使用高级消息传递将结果推送到具有相同搜索关键字的用户。这将节省资源并有助于实现更好的性能。

谢谢,问题已解决:

private static final Map<Object, List<Locker<Object, String>>> CONCURRENT_SEARCHES = new ConcurrentHashMap<>();


public String search(Map<String, Object> params) {
    Object key = params.get("keyword");
    assert key != null;
    Locker<Object, String> locker = new Locker<>(key);
    if (isInProgress(key, locker)) {
        locker.lock();
        String result = locker.getValue();
        return result == null ? "[]" : result;
    }
    String result = /*search*/;
    finished(key, result);
    return result;
}

private static synchronized boolean isInProgress(Object key, Locker<Object, String> locker) {
    List<Locker<Object, String>> list = CONCURRENT_SEARCHES.get(key);
    if (list != null) {
        list.add(locker);
        return true;
    }
    CONCURRENT_SEARCHES.put(key, Collections.synchronizedList(new ArrayList<>()));
    return false;
}

private static synchronized void finished(Object key, String result) {
    Optional.of(CONCURRENT_SEARCHES)
            .map(searches -> searches.remove(key))
            .ifPresent(list -> {
                list.stream().forEach(locker -> {
                    locker.setValue(result);
                    locker.unlock();
                });
                list.clear();
            });
}
private static final Map CONCURRENT_search=new ConcurrentHashMap();
公共字符串搜索(映射参数){
对象键=params.get(“关键字”);
断言键!=null;
储物柜=新储物柜(钥匙);
如果(isInProgress(钥匙、储物柜)){
locker.lock();
字符串结果=locker.getValue();
返回结果==null?[]:结果;
}
字符串结果=/*搜索*/;
完成(关键、结果);
返回结果;
}
私有静态同步布尔isInProgress(对象密钥、锁柜){
List List=并发搜索。get(键);
如果(列表!=null){
添加(储物柜);
返回true;
}
并发搜索.put(key,Collections.synchronizedList(newarraylist());
返回false;
}
私有静态同步无效已完成(对象键、字符串结果){
可选.of(并发搜索)
.map(搜索->搜索.remove(键))
.ifPresent(列表->{
list.stream().forEach(locker->{
locker.setValue(结果);
locker.unlock();
});
list.clear();
});
}

您可以缓存搜索,但不缓存搜索结果。因此,如果没有正在进行的关键字搜索,即使之前进行过类似的搜索,也会启动一个新的关键字。搜索结果不是固定的,以后可能会因某些原因而更改…那么测试运行的问题是什么?大多数搜索都与以前的搜索相结合。这不是你想做的吗?
private static final Map<Object, List<Locker<Object, String>>> CONCURRENT_SEARCHES = new ConcurrentHashMap<>();


public String search(Map<String, Object> params) {
    Object key = params.get("keyword");
    assert key != null;
    Locker<Object, String> locker = new Locker<>(key);
    if (isInProgress(key, locker)) {
        locker.lock();
        String result = locker.getValue();
        return result == null ? "[]" : result;
    }
    String result = /*search*/;
    finished(key, result);
    return result;
}

private static synchronized boolean isInProgress(Object key, Locker<Object, String> locker) {
    List<Locker<Object, String>> list = CONCURRENT_SEARCHES.get(key);
    if (list != null) {
        list.add(locker);
        return true;
    }
    CONCURRENT_SEARCHES.put(key, Collections.synchronizedList(new ArrayList<>()));
    return false;
}

private static synchronized void finished(Object key, String result) {
    Optional.of(CONCURRENT_SEARCHES)
            .map(searches -> searches.remove(key))
            .ifPresent(list -> {
                list.stream().forEach(locker -> {
                    locker.setValue(result);
                    locker.unlock();
                });
                list.clear();
            });
}