我已经开始在Java中学习并发和线程。我知道同步的基础知识(即它的作用)。从概念上讲,我理解它提供了对Java中多个线程的共享资源的互斥访问。但是当遇到像下面这样的例子时,我很困惑,让它同步是否是一个好主意。我知道应该同步代码的关键部分,不应该过度使用此关键字,否则会影响性能。
public static synchronized List<AClass> sortA(AClass[] aArray)
{
List<AClass> aObj = getList(aArray);
Collections.sort(aObj, new AComparator());
return aObj;
}
public static synchronized List<AClass> getList(AClass[] anArray)
{
//It converts an array to a list and returns
}
答案 0 :(得分:12)
假设每个线程都传递一个不同的数组,那么就不需要同步,因为其余的变量都是本地的。
相反,如果您启动了几个线程全部调用sortA
并将引用传递给同一个数组,您将遇到麻烦没有synchronized
,因为它们会互相干扰。
请注意,从示例中可以看出getList
方法从数组中返回一个新的List
,这样即使线程传递相同的数组,也会得到不同的List
对象。这是误导。例如,使用Arrays.asList
创建一个由给定数组支持的List
,但javadoc明确指出Changes to the returned list "write through" to the array.
因此请小心。
答案 1 :(得分:5)
当您在多个调用之间共享数据时,通常需要进行同步,并且可能会修改数据,从而导致不一致。如果数据是只读的,那么您不需要同步。
在上面的代码段中,没有共享的数据。这些方法对提供的输入起作用并返回输出。如果多个线程调用您的某个方法,则每个调用都有自己的输入和输出。因此,任何地方都不存在不一致的可能性。因此,上述代码段中的方法无需同步。
如果不必要地使用同步,由于涉及的开销,肯定会降低性能,因此只有在需要时才应谨慎使用。
答案 2 :(得分:2)
您的静态方法不依赖于任何共享状态,因此无需同步。
答案 3 :(得分:2)
没有定义规则,比如何时使用synchronized,当不确定时,如果您确定并发线程不会访问您的代码,那么您可以避免使用synchronized。
答案 4 :(得分:2)
正确计算的同步会对应用程序的吞吐量产生影响,并且还会导致饥饿线程。
所有get基本上都应该是非阻塞的,因为并发包下的Collections已经实现了。
在您的示例中,所有调用线程都将传递自己的数组副本,getList
不需要同步,因此所有其他变量都是本地的sortA
方法。
局部变量存在于堆栈中,每个线程都有自己的堆栈,因此其他线程不会干扰它。
当您更改其他线程应在一致状态下看到的Object的状态时,如果您的调用不会更改您不需要同步的对象的状态,则需要同步。
答案 5 :(得分:2)
我不会在单线程代码上使用synchronized
。即多个线程无法访问对象的情况。
这可能看似显而易见但是JDK中使用的~99%的StringBuffer只能被一个线程使用,可以用StringBuilder替换(不同步)