Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 这个静态方法是线程安全的还是需要同步_Java_Multithreading_Concurrency_Thread Safety - Fatal编程技术网

Java 这个静态方法是线程安全的还是需要同步

Java 这个静态方法是线程安全的还是需要同步,java,multithreading,concurrency,thread-safety,Java,Multithreading,Concurrency,Thread Safety,我有一个实用程序类,它有一个静态方法来修改输入数组列表的值。此静态方法由调用方调用。调用方用于处理web服务请求。对于每个请求(每个线程),调用方创建一个新的ArrayList并调用静态方法 public class Caller{ public void callingMethod(){ //Get Cloned criteria clones a preset search criteria that has place holders for values and re

我有一个实用程序类,它有一个静态方法来修改输入数组列表的值。此静态方法由调用方调用。调用方用于处理web服务请求。对于每个请求(每个线程),调用方创建一个新的ArrayList并调用静态方法

public class Caller{

   public void callingMethod(){

     //Get Cloned criteria clones a preset search criteria that has place holders for values and returns a new ArrayList of the original criteria. Not included code for the clone
     ArrayList<Properties> clonedCriteria = getClonedCriteria();

     CriteriaUpdater.update(clonedCriteria , "key1", "old_value1", "key1_new_value");
     CriteriaUpdater.update(clonedCriteria , "key2", "old_value2", "key2_new_value");

    //do something after the this call with the modified criteria arraylist
   }

}

public class CriteriaUpdater
{
    //updates the criteria, in the form of array of property objects, by replacing the token with the new value passed in
    public static void update(ArrayList<Properties> criteria, String key, String token, String newValue)
    {
        for (Properties sc: criteria)
        {
            String oldValue = sc.getProperty(key);
            if ((oldValue != null) && (oldValue.equals(token))) 
                sc.setProperty(key, newValue);
        }
    }
}
公共类调用者{
公共无效调用方法(){
//获取克隆条件克隆具有值占位符的预设搜索条件,并返回原始条件的新ArrayList。克隆的代码不包括在内
ArrayList clonedCriteria=getClonedCriteria();
更新(克隆标准,“key1”、“旧值1”、“key1\u新值”);
CriteriaUpdater.update(clonedCriteria,“key2”,“old_value2”,“key2_new_values”);
//使用修改后的条件arraylist在此调用后执行某些操作
}
}
公共类标准更新程序
{
//通过使用传入的新值替换标记,以属性对象数组的形式更新条件
公共静态无效更新(ArrayList条件、字符串键、字符串标记、字符串newValue)
{
对于属性(sc:标准)
{
字符串oldValue=sc.getProperty(键);
如果((oldValue!=null)&&(oldValue.equals(令牌)))
sc.setProperty(键,newValue);
}
}
}
以下是标准的克隆方式:

public synchronized static ArrayList<Properties> cloneSearchCriteria(ArrayList<Properties> criteria) { 
  if (criteria == null) return null; 
  ArrayList<Properties> criteriaClone = new ArrayList<Properties>(); 
  for (Properties sc : criteria) { 
    Properties clone = new Properties(); 
    Enumeration propertyNames = sc.propertyNames(); 
    while (propertyNames.hasMoreElements()) { 
      String key = (String) propertyNames.nextElement(); 
      clone.put(key, (String) sc.get(key)); 
    } 
    criteriaClone.add(clone);
  } 
  return criteriaClone; 
}
公共同步静态ArrayList cloneSearchCriteria(ArrayList criteria){
if(criteria==null)返回null;
ArrayList criteriaClone=新的ArrayList();
对于(属性sc:criteria){
属性克隆=新属性();
枚举propertyNames=sc.propertyNames();
而(propertyNames.hasMoreElements()){
字符串键=(字符串)propertyNames.nextElement();
clone.put(key,(String)sc.get(key));
} 
criteriaClone.add(克隆);
} 
返回标准克隆;
}
根据上述定义,通过不同步静态方法,它仍然能够正确处理并发方法调用。我的理解是,我必须同步此方法以实现并发性,但我想确认一下。 我知道每个线程都有自己的堆栈,但对于静态方法,它对所有线程都是通用的——所以在这种情况下,如果我们不同步,它不会导致问题吗? 感谢您的建议和任何更正


谢谢

您的比赛条件有问题。至少底层的
属性
数据结构永远不会损坏,但可能有不正确的值。特别是,本节中可以包含任意数量的线程,这意味着最终值可以是任何线程中的任何内容

        String oldValue = sc.getProperty(key);
        if ((oldValue != null) && (oldValue.equals(token))) 
            sc.setProperty(key, newValue);

我假设您的列表从未更改过,但如果更改过,则必须同步
。您可以锁定该类,但锁定正在更改的集合可能是更好的选择。

您是正确的,因为每个线程都有自己的堆栈,因此每个线程在调用
update()
时都有自己的局部变量和方法参数副本。当它运行时,它将把那些局部变量和方法参数保存到它的堆栈中


但是,方法参数
criteria
是对将存储在Java对象所在堆上的可变对象的引用。如果线程可以在同一个ArrayList上调用
update()
,或者ArrayList中包含的元素可能包含在多个ArrayList中,这些ArrayList被不同的线程传递到
update()
的不同调用中,则可能会发生同步错误。

这一切都取决于
getClonedCriteria()
方法。这就是访问共享状态的方法

您正在创建标准的“深度副本”,以便每个克隆都独立于原始克隆,并且彼此独立

但是还有一个更微妙的问题,那就是对原型标准执行的任何初始化都必须在任何线程读取标准以克隆它之前发生。否则,克隆线程可能会读取数据结构的未初始化版本


实现这一点的一种方法是在静态初始值设定项中初始化原型条件,并将其分配给类成员变量。另一种方法是初始化条件,然后将其分配给
volatile
变量。或者,您可以初始化原型并将其分配给
synchronized
块内的普通类或实例成员变量(或使用
锁),然后从同一个锁上同步的另一个块读取变量。

另一个线程是否更改过“预设搜索条件”?“在线程之间共享任何数据后执行操作”是否执行任何操作?
getClonedCriteria
是否返回同步副本,或仅返回参考副本?预设条件不会更改。公共同步静态ArrayList cloneSearchCriteria(ArrayList criteria){if(criteria==null)返回null;ArrayList criteriaClone=new ArrayList();for(Properties sc:criteria){Properties clone=new Properties();枚举propertyNames=sc.propertyNames();而(propertyNames.hasMoreElements()){String key=(String)propertyNames.nextElement();clone.put(key,(String)sc.get(key));}criteriaClone.add(clone);}return criteriaClone;}抱歉。无法格式化代码..但cloneSearchCriteria()已重命名为getClonedCriteria()对于已同步的此帖子,您仍然没有显示原始条件是如何初始化的。
cloneSearchCriteria()
如果您正确处理原始条件,则不需要同步方法。不确定我是否正确理解您。公共同步静态ArrayList cloneSearchCriteria(ArrayList criteria){if(criteria==null)返回null;ArrayList criteriaClone=new ArrayList();for(属性sc:criteria){