封装ConcurrentHashMap,但仍然是并发的

问题描述

对于一个班级项目,我正在使用并发HashMap来包含活动用户及其连接详细信息的列表。多个线程应该能够获取所有活动用户的列表,其中5个线程能够修改hashMap。当我对其进行测试时,它似乎可以工作,但是我不知道线程是否被阻塞并且系统是否足够快。

  • 我想封装并发HashMap,但是我不知道这是否会阻止其并发?
  • 我还希望哈希表只有一个版本,所以我将该类设为枚举,很糟糕,只是让 main 可以创建它?
  • 我不希望其他线程修改hashMap,所以我不传递集合/迭代器。有没有没有删除就可以传递收藏的方法吗?
  • (新)我在CoolFeature中调用了两种方法,一种是阻塞,另一种不是。两者都可以有自己的位置。论文有什么问题吗?

我们正在使用Akka Actors创建线程并处理并发性,下面是我的简化代码。这不是分配问题,只是我作为项目一部分创建的内容的一部分。

编辑:我更改了代码,拥有一个不依赖Akka的解决方案将是一件好事,这样其他人可以找到有用的答案。

package server.management;
public class Sessions {
  static final ConcurrentHashMap<Integer,Id<User>> sessions = new concurrentHashMap<>();
  private Sessions() { }
}

public class SessionManager {
  public static void create(int connection,Id<User> userId) {
    // checks
    Sessions.sessions.put(connection,userId);
  }

  public static Id<User> getUser(int connection) {
    Id<User> userId = Sessions.sessions.get(connection);
    return userId;
  }

  public static ArrayList<Id<User>> getActiveUsers() {
    ArrayList<Id<User>> list = new ArrayList<>();

    // Don't pass the sessions.values() directly because the Map can be modified.
    for (Id<User> userId : Sessions.sessions.values()) {
      list.add(userId);
    }
    return list;
  }

  // other methods
}

/* Another thread/akka actor class */
package server;
import server.management.SessionManager;

public class CoolFeature extends AbstractActor {
  ...
  Id<User> client = SessionManager.getUser(1023);
  // do stuff
  CompletableFuture<ArrayList<Id<User>>> futureList =
      CompletableFuture.supplyAsync(SessionManager::getActiveUsers);
  // do stuff
  ArrayList<Id<User>> list = futureList.get();
  // do stuff
}

解决方法

使用akka actor,您可以将正常Map放在actor中作为状态,而不必担心并发访问,因为使用actor模型,actor一次只能处理一条消息。您可以执行以下操作。该代码在Scala中,但您明白我的想法。

object Manager {
  case class Get(id: Int)
  case object GetActive
  case class Create(connId: Int,userId: Int)
}

class Manager extends Actor {
  import Manager._
  val sessions = mutable.Map[Int,Int].empty
  override def receive = {
    case Get(id) => sessions.get(id)
    case GetActive => sessions.values
    case Create(connId,userId) => sessions += (connId -> userId)
  }
}

如果您有任何问题,请告诉我。