提问者:小点点

我是否必须将类扩展到并发HashMap,或者我可以为线程安全使用变量并发HashMap


我正在创建基于Socket的Server-Client预订服务,并且有关于将被多个线程访问的类的问题,它是否需要扩展并发HashMap或者是否足以创建变量并发HashMap以确保线程安全?

我有两个想法,但我不确定第一个是否可行,所以第一个想法是创建只实现Serializable的类,该类具有可变日期,然后是线程想要操作的变量并发哈希映射,第二个想法是拥有扩展并发哈希映射的类,只是CHP,但带有附加变量以确保它与其他变量可区分

public class Day implements Serializable {
private LocalDate date;
private ConcurrentHashMap<String, Boolean> schedule;

public Day(LocalDate date){
    this.date = date;
    this.schedule = new ConcurrentHashMap<>();
    IntStream.range(10, 18).forEachOrdered(
            n -> this.schedule.put(LocalTime.of(n, 0).toString(), TRUE));
}

public void changeaval(String key,Boolean status) {
    this.schedule.replace(key,status);
}

public boolean aval(String key){
    return this.schedule.get(key);
}

public LocalDate getDate(){return this.date;}

public ConcurrentHashMap getSchedule(){return this.schedule;}

}

我只想拥有可以被多个线程访问并且可以与其他线程区分开来的Class/Object/可比较并且具有映射Int的并发HashMap-


共2个答案

匿名用户

在处理由多个线程访问的对象时,基本上需要注意两件事:

  1. 竞争条件-由于操作系统的线程调度和编译器的指令重新排序优化,指令以程序员不希望的顺序执行,从而导致错误
  2. 内存可见性-在多处理器系统中,一个处理器所做的更改并不总是立即对其他处理器可见。出于性能原因,处理器将内容保存在本地寄存器和缓存中,因此对其他处理器正在执行的线程不可见。

幸运的是,我们可以使用适当的同步来处理这两种情况。

让我们谈谈这个特殊的程序。

Localdate本身是一个不可变且线程安全的类。如果我们查看这个类的源代码,我们会看到这个类的所有字段都是last。这意味着一旦Localdate的构造函数完成对象的初始化,对象本身将跨线程可见。但是当它被分配给不同对象中的引用变量时,赋值(换句话说,引用变量的内容)是否会对其他线程可见是我们需要注意的。

给定您的情况下的构造函数,我们可以确保字段date跨线程的可见性,前提是dateend易失性。由于您没有修改类中的date字段,因此您可以很好地将其设为最终字段,从而确保安全初始化。如果您后来决定为该字段设置一个setter方法(取决于您的业务逻辑和设计),您应该使字段易失性而不是最终易失性创建了一个发生前关系,这意味着在写入易失性变量之前在特定线程中执行的任何指令一旦读取相同的易失性变量,其他线程就会立即看到。

ConCurrentHashMap也是如此。您应该使字段计划最终。由于ConCurrentHashMap本身具有所有必要的同步,因此当其他线程尝试读取它时,您针对键设置的任何值都将对其他线程可见。

但是请注意,如果您有一些可变对象作为ConCurrentHashMap值而不是Boolean,则必须以与上述相同的方式设计它。

此外,最好知道有一个称为搭载的概念,这意味着如果一个线程写入其所有字段,然后写入易失性变量,则该线程在写入易失性变量之前写入的所有内容都将对其他线程可见,前提是其他线程在第一个线程写入易失性变量后首先读取该变量的值。但是当您这样做时,您必须非常小心地确保读写顺序,并且容易出错。所以,这是在你想从一段罕见的代码中挤出最后一滴性能时完成的。在性能之前有利于安全性、可运维性、易读性。

最后,代码中没有竞争条件。唯一正在发生的写入是在ConCurrentHashMap上,它本身是线程安全的。

匿名用户

基本上,这两种方法是等价的。从架构的角度来看,在专用类中创建变量是首选的,因为可以更好地控制哪些方法可供用户访问。在扩展时,用户可以访问底层ConCurrentHashMap的许多方法并滥用它们。