简体   繁体   English

我是否必须将类扩展到 ConcurrentHashMap 或者我可以为 threadSafety 使用变量 ConcurrentHashMap

[英]Do I have to extend class to ConcurrentHashMap or can I have variable ConcurrentHashMap for threadSafety

I am creating Socket based Server-Client reservation service, and have problem about class which will be accessed by multiple threads, does it need to Extend ConcurrentHashMap or is it enough to create variable ConcurrentHashMap to be thread safe?我正在创建基于 Socket 的服务器-客户端保留服务,并且有关于将被多个线程访问的类的问题,是否需要扩展 ConcurrentHashMap 或者创建变量 ConcurrentHashMap 是否足以保证线程安全?

I have two ideas but I am not sure if first one will work, so the first one would be creating class which only implements Serializable has variable date and then variable ConcurrentHashMap on which threads want to operate, second idea is to have class which extends Concurrent Hash Map and just is CHP but with addiontal variable to make sure it is distinguishable from others我有两个想法,但我不确定第一个是否可行,所以第一个将创建仅实现 Serializable 的类,该类具有可变日期,然后是线程想要操作的变量 ConcurrentHashMap,第二个想法是拥有扩展 Concurrent 的类哈希映射,只是 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;}

}

I just want to have Class/Object which can be accessed by multiple threads and can be distinguishable from others/comparable and has ConcurrentHashMap which maps Int -> Boolean This is the first time I am using Stack and It is my first project in Java so I don't know much sorry if something is not right.我只想拥有可以由多个线程访问的类/对象,并且可以与其他线程/可比较的对象区分开来,并且具有映射 Int -> Boolean 的 ConcurrentHashMap 这是我第一次使用 Stack,这是我在 Java 中的第一个项目如果有什么不对的地方,我不知道很抱歉。

There are basically two things to look out for when dealing with objects accessed by multiple threads:在处理多线程访问的对象时,基本上有两件事需要注意:

  1. Race condition - Due to thread scheduling by the operating system and instruction reordering optimizations by the compiler, the instructions are executed in a order not intended by the programmer causing bugs竞争条件 - 由于操作系统的线程调度和编译器的指令重新排序优化,指令以程序员不希望的顺序执行,导致错误
  2. Memory visibility - In a multi processor system, changes made by one processor is not always immediately visible to other processors.内存可见性 - 在多处理器系统中,一个处理器所做的更改并不总是立即对其他处理器可见。 Processors keep things in their local registers and caches for performance reasons and therefore not visible to threads being executed by other processors.出于性能原因,处理器将内容保存在其本地寄存器和缓存中,因此对其他处理器正在执行的线程不可见。

Luckily we can handle both these situation using proper synchronizations.幸运的是,我们可以使用适当的同步来处理这两种情况。

Let's talk about this particular program.让我们来谈谈这个特定的程序。

Localdate by itself is an immutable and thread safe class. Localdate本身是一个不可变的线程安全类。 If we look at the source code of this class, we'd see that all the fields of this class are final .如果我们查看这个类的源代码,我们会看到这个类的所有字段都是final This means that as soon as the constructor of Localdate finishes initializing the object, the object itself will be visible across threads.这意味着只要Localdate的构造Localdate完成对象的初始化,对象本身就会跨线程可见。 But when it is assigned to a reference variable in a different object, whether the assignment (in other words, the content of the reference variable) would be visible to other threads or not is what we need to look out for.但是当它被赋值给不同对象中的引用变量时,这个赋值(即引用变量的内容)是否对其他线程可见是我们需要注意的。

Given the constructor in your case, we can ensure the visibility of the field date across threads provided date is either final or volatile .鉴于您的情况下的构造函数,我们可以确保字段date跨线程的可见性提供的datefinalvolatile Since you are not modifying the date field in your class, you can very well make it final and that ensures safe initialization.由于您没有修改类中的date字段,因此您可以很好地将其设为 final,从而确保安全初始化。 If you later decide to have a setter method for this field (depending on your business logic and your design), you should make the field volatile instead of final .如果您稍后决定为此字段使用 setter 方法(取决于您的业务逻辑和您的设计),您应该将该字段设置为volatile而不是final volatile creates a happens-before relationship which means that any instruction that is executed in the particular thread before writing to the volatile variable would be immediately visible to the other threads as soon as they read the same volatile variable. volatile创建了一个发生在之前的关系,这意味着在写入volatile变量之前在特定线程中执行的任何指令将立即对其他线程可见,一旦它们读取相同的 volatile 变量。

Same goes for ConcurrentHashMap . ConcurrentHashMap You should make the field schedule final .您应该使现场schedule final Since ConcurrentHashMap by itself has all the necessary synchronizations in it, any value you set against a key would be visible to the other threads when they try to read it.由于ConcurrentHashMap本身具有所有必要的同步,因此当其他线程尝试读取它时,您针对键设置的任何值都将可见。

Note, however, that if you had some mutable objects as ConcurrentHashMap values instead of Boolean , you would have to design it in the same way as mentioned above.但是请注意,如果您有一些可变对象作为ConcurrentHashMap值而不是Boolean ,则必须以与上述相同的方式设计它。

Also, it may be good to know that there is a concept called piggy-backing which means that if one thread writes to all its fields and then writes to a volatile variable, everything written by the thread before writing to the volatile variable would be visible to the other threads, provided the other threads first read value of the volatile variable after it is written by the first thread.此外,知道有一个叫做piggy-backing的概念可能会很好,这意味着如果一个线程写入其所有字段然后写入volatile变量,则该线程在写入volatile变量之前写入的所有内容都是可见的给其他线程,前提是其他线程在第一个线程写入后首先读取volatile变量的值。 But when you do this you have to ensure very carefully the sequence of reading and writing and it is error prone.但是当你这样做时,你必须非常仔细地确保读取和写入的顺序,而且很容易出错。 So, this is done when you want to squeeze out the last drop of performance from the piece of code which is rare.因此,当您想从一段罕见的代码中挤出最后一滴性能时,就会这样做。 Favor safety, maintainability, readability before performance.在性能之前优先考虑安全性、可维护性、可读性。

Finally, there is no race condition in the code.最后,代码中没有竞争条件。 The only write that is happening is on the ConcurrentHashMap which is thread safe by itself.发生的唯一写入是在ConcurrentHashMap ,它本身是线程安全的。

Basically, both approaches are equivalent.基本上,这两种方法是等效的。 From architectural point of view, making a variable inside dedicated class is preferred because of better control of which methods are accessible to the user.从架构的角度来看,在专用类中创建变量是首选,因为可以更好地控制用户可以访问哪些方法。 When extending, a user can access many methods of underlying ConcurrentHashMap and misuse them.在扩展时,用户可以访问底层 ConcurrentHashMap 的许多方法并滥用它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM