任何人都可以告诉我,如果我是对的吗?我有两个并行运行的线程。
class MyThread extends Thread {
MyThread() {
}
method1() {
}
method2() {
}
method3() {
}
approach(1):
run() {
method1();
method2();
method3();
}
approach(2):
run() {
//the code of method1 is here (no method calling)
//the code of method2 is here (no method calling)
//the code of method3 is here (no method calling)
}
}
class Test{
public static void main(){
Thread t1 = new Thread();
t1.start();
Thread t2 = new Thread();
t2.start();
}
}
method1
,method2
和method3
不访问全局共享数据,但是它们的代码在方法部分中执行局部变量写入,因此我想我不能允许重叠执行在方法部分内。
由此:
在approach(1)
:我需要让方法(method1
,method2
和method3
)同步,对吧?
approach(2)
中的:无需同步代码部分,对吧?
如果我在两种方法中都是对的,使用approach(2)
会提供更好的表现,对吗?
答案 0 :(得分:3)
简短回答:您不需要同步。从线程安全角度来看,这两种方法都是等效的。
更长的答案:
退一步并记住同步块的作用可能是值得的。它基本上做了两件事:
请注意,synchronized方法只是将方法代码包装在synchronized(this){...}中的简写。
除了这两件事之外,Java内存模型(JMM)保证在一个线程中,事情会发生,好像它们没有被重新排序一样。 (它们实际上可能因各种原因重新排序,包括效率 - 但不是程序在单个线程中可以注意到的方式。例如,如果你执行“x = 1; y = 2”,编译器可以自由切换y = 2发生在x = 1之前,因为单个线程实际上不能注意到差异。如果多个线程正在访问x和y,那么很可能在没有适当同步的情况下,另一个线程看到y = 2在它看到x = 1之前。)
所以,回到原来的问题,有几个有趣的笔记。
首先,由于同步方法是将整个方法放在“synchronized(this){...}”块中的简写,因此t1的方法和t2的方法不会与同一个引用同步,因此不会相对于彼此同步。 t1的方法只与t1对象同步,而t2只与t2同步。换句话说,t1.method1()和t2.method1()同时运行完全没问题。因此,在synchronized关键字提供的这两件事中,第一个(进入块的排他性)是不相关的。事情可能会像:
至于同步的第二件事(建立发生在之前),使method1()和method2()同步将基本上确保t1.method1()发生在t1.method2()之前。但是由于这两个都发生在同一个线程上(t1线程),JMM无论如何都保证会发生这种情况。
所以它实际上变得更加丑陋。如果t1和t2确实共享状态 - 也就是说,同步是必要的 - 那么使方法同步将不就足够了。请记住,同步方法意味着同步(this){...},因此t1的方法将与t1同步,而t2将与t2同步。你实际上不会在t1的方法和t2之间建立任何先发生过的关系。
相反,您必须确保在同一参考上同步方法。有很多方法可以做到这一点,但基本上,它必须是对两个线程都知道的对象的引用。
假设t1和t2都知道相同的参考,LOCK。两者都有类似的方法:
method1() {
synchronized(LOCK) {
// do whatever
}
}
现在事情可能会像这样:
答案 1 :(得分:1)
您说您的方法不访问全局共享数据并且只写本地变量,因此不需要同步它们因为两个线程都有自己的局部变量副本。它们不会重叠或什么的。
在静态/类变量的情况下面临这种问题。如果多个线程试图同时更改静态变量的值,则会出现问题,因此需要进行同步。
答案 2 :(得分:0)
如果您正在调用的方法不写入全局共享数据,则不必同步它们。
在多线程程序中,每个线程都有自己的调用堆栈。每个方法的局部变量在每个线程中都是独立的,不会相互覆盖。
因此,方法1工作正常,不需要同步开销,并且是更好的编程实践,因为它避免了重复的代码。
答案 3 :(得分:0)
线程明确你的确定。方法中的局部变量不在线程之间共享,因为在线程中运行的每个实例都有自己的堆栈。
两种方法之间不会有任何速度提升,它只是更好的代码组织(更简单的方法更容易理解)
如果每个方法都独立于另一个方法,您可能需要考虑它们是否属于同一个类。如果您希望性能增益创建3个不同的类并为每个方法执行多个线程(性能增益取决于可用内核的数量cpu / io ration等。)
答案 4 :(得分:0)
因此:在方法(1)中:我需要制作方法(method1,method2 和方法3)同步,对吗?方法(2):没有必要 同步代码部分,对吧?
调用内联方法v / s调用多个方法不会确定方法是否应该同步。我建议您read this,然后要求进一步澄清。
如果我在这两种方法中都是正确的,那么使用方法(2)会提供更好的性能,对吗?
以将方法分解为单神方法为代价?当然,但与失去的代码可读性相比,你会看到一个“非常”微小的改进,绝对不推荐。
答案 5 :(得分:0)
方法1,2和3不会同时执行,因此如果它们读/写的变量在运行时没有与其他线程共享,那么就不需要同步,也不需要内联。 / p>
如果他们修改了其他线程在运行的同时读取的数据,那么您需要保护对该数据的访问权限。
如果他们读取其他线程将在其运行的同时写入的数据,那么您需要保护对该数据的访问。
如果期望其他线程读取方法1,2或3修改的数据,则需要使run方法同步(或者在同步块中)以设置门,以便JVM设置memory barrier并确保其他线程在m1,2和3完成后可以看到数据。