我正在创建基于Socket的服务器-客户端预留服务,并且对将由多个线程访问的类有问题,是否需要扩展ConcurrentHashMap还是足以创建变量ConcurrentHashMap以确保线程安全?
我有两个想法,但是我不确定第一个想法是否可以工作,因此第一个想法是创建仅实现Serializable的类,该类具有可变的date,然后创建变量ConcurrentHashMap,线程要在该变量上运行,第二个想法是拥有类扩展了并发哈希图,它只是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,并且具有ConcurrentHashMap来映射Int-> Boolean 这是我第一次使用Stack,这是我在Java中的第一个项目,因此对于某些错误,我并不感到很遗憾。
答案 0 :(得分:1)
在处理由多个线程访问的对象时,基本上要注意两件事:
幸运的是,我们可以使用适当的同步来处理这两种情况。
让我们谈谈这个特定的程序。
Localdate
本身是一个不可变且线程安全的类。如果我们查看此类的源代码,则会看到此类的所有字段均为final
。这意味着Localdate
的构造函数完成对对象的初始化后,对象本身将在线程之间可见。但是,当将其分配给其他对象中的参考变量时,我们需要注意的是分配(换句话说,参考变量的内容)是否对其他线程可见。
鉴于您所使用的构造函数,我们可以确保在{strong>提供的提供的线程中字段date
的可见性 date
是final
或{{1} }。由于您没有修改类中的volatile
字段,因此可以很好地将其定型,并确保安全的初始化。如果您以后决定对此字段使用setter方法(取决于您的业务逻辑和设计),则应将字段date
代替volatile
。 final
创建一个 happens-before 关系,这意味着在写入volatile
变量之前在特定线程中执行的任何指令将立即对其他线程可见。因为他们读取了相同的volatile变量。
volatile
也一样。您应将字段ConcurrentHashMap
设为schedule
。由于final
本身具有所有必要的同步,因此您为键设置的任何值在其他线程尝试读取它时都将可见。
但是,请注意,如果您有一些可变对象作为ConcurrentHashMap
值而不是ConcurrentHashMap
,则必须采用与上述相同的方法进行设计。
此外,最好知道一个名为 piggy-backing 的概念,这意味着如果一个线程写入其所有字段,然后写入Boolean
变量,只要其他线程在第一个线程写入volatile
变量后首先读取该变量的值,其他线程就可以看到该线程在写入volatile
变量之前写入的所有内容。但是,当您执行此操作时,必须非常仔细地确保读和写的顺序,并且容易出错。因此,当您想从一段罕见的代码中挤出最后的性能下降时,可以这样做。优先考虑安全性,可维护性和性能易读性。
最后,代码中没有竞争条件。唯一发生的写操作是volatile
本身具有线程安全性。
答案 1 :(得分:0)
基本上,两种方法都是等效的。从体系结构的角度来看,最好在专用类中创建变量,因为可以更好地控制用户可以访问哪些方法。扩展时,用户可以访问基础ConcurrentHashMap的许多方法并滥用它们。