Jou*_*las 2 java multithreading synchronized
假设我有一个相对简单的对象,具有两个属性:
@Data
public class MyObject {
public Integer a;
public Integer b;
}
Run Code Online (Sandbox Code Playgroud)
我可以安全地在某个线程中改变 a 并在其他线程中安全地改变 b 吗?例如,这段代码不会受到竞争条件的影响吗?
public MyObject compute() {
MyObject newObj = new MyObject();
List<Runnable> tasks = new ArrayList<>();
Runnable computeATask = () -> {
Integer a = computeA();
newObj.setA(a);
};
Runnable computeBTask = () -> {
Integer b = computeB();
newObj.setB(b);
};
tasks.add(computeATask);
tasks.add(computeBTask);
tasks.stream().parallel().forEach(Runnable::run);
return newObj;
}
Run Code Online (Sandbox Code Playgroud)
\n\nJava 虚拟机实现的一个考虑因素是每个字段和数组元素都被认为是不同的;对一个字段或元素的更新不得与任何其他字段或元素的读取或更新交互。
\n
a因此,可能由与示例中不同的线程编写的事实b不会造成任何数据争用。
但它仍然需要一个线程安全的机制来读取结果。在您的示例中,它\xe2\x80\x99是并行流,保证启动线程在forEach返回后可以安全地读取两个变量。
你的例子可以简化为
\npublic MyObject compute() {\n MyObject newObj = new MyObject();\n Stream.<Runnable>of(() -> newObj.setA(computeA()), () -> newObj.setB(computeB()))\n .parallel().forEach(Runnable::run);\n return newObj;\n}\nRun Code Online (Sandbox Code Playgroud)\n但推荐的模式是先执行计算,然后构造对象,然后可以将其设计为不可变对象。
\npublic class MyObject {\n public final Integer a, b;\n\n public MyObject(Integer a, Integer b) {\n this.a = a;\n this.b = b;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\npublic MyObject compute() {\n return CompletableFuture.supplyAsync(() -> computeA())\n .thenCombine(CompletableFuture.supplyAsync(() -> computeB()), MyObject::new)\n .join();\n}\nRun Code Online (Sandbox Code Playgroud)\n这样,您可以确保任何看到该字段的线程都MyObject将看到一致的字段值,无论其余应用程序中发生什么情况。
| 归档时间: |
|
| 查看次数: |
64 次 |
| 最近记录: |