简体   繁体   English

如何使这个函数线程安全?

[英]How to make this function thread safe?

public class Sol {



    static Map<Integer, List<String>> emap;
    static List<Integer> sortSalaries(List<List<String>> workers) {
        List<Integer> res = new ArrayList<Integer>();
        emap = new HashMap<>();
        for (List<String> e: workers)
            emap.put(Integer.parseInt(e.get(0)), e);

        for(List<String> worker: workers )
        {
         //accessing workers
         .....
        }


        Collections.sort(res);

        return res;


    }

    public static int dfs(int eid) {
        List<String> employee = emap.get(eid);
        int salary=0;
        String ans = employee.get(3);
        for (int i=0;i<ans.length();i=i+2)

        {
            // accesing emap
          ......
        }

        return salary;
    }


}

Do i have to use synchronized keyword to make it thread safe.我是否必须使用 synchronized 关键字才能使其线程安全。 Do i have to use Vector and Hashtable if method is synchronized.如果方法是同步的,我是否必须使用 Vector 和 Hashtable。

Alternatively, What if i use Vector and Hashtable, move the emap variable to sortSalaries() and pass it to dfs() .或者,如果我使用 Vector 和 Hashtable,将emap变量移动到sortSalaries()并将其传递给dfs() Is it okay if i not use synchronized keyword in this case..如果我在这种情况下不使用synchronized 关键字可以吗..

  1. Protect emap from outer access保护emap免受外部访问
  2. Init emap to exclude NPE初始化emap以排除NPE

Example:例子:

public final class Sol {

    private static final Map<Integer, List<String>> emap = new HashMap<>();

    static List<Integer> sortSalaries(List<List<String>> workers) {
        synchronized (Foo.class) {
            for (List<String> e : workers)
                emap.put(Integer.parseInt(e.get(0)), e);
        }

        // do smth, not access emap
    }

    public static synchronized int dfs(int eid) {
        // do smth with accessing emap
    }
}

In sortSalaries you can minimize synchoronized block with for loop .sortSalaries可以最大限度地减少synchoronized块与for loop In dfs you access emap in different places of the method and therefore you have to synchoonized enire method.dfs您在方法的不同位置访问emap ,因此您必须同步整个方法。

Using either ConcurrentHashMap or Vector do not help here, becuase betwee get/set elements to the collection, they could be changed, which is not OK for dfs method: it should feeze emap when it's called.使用ConcurrentHashMapVector在这里无济于事,因为在get/set元素到集合之间,它们可以被更改,这对于dfs方法来说是不合适的:它应该在emap时处理emap

I asked you question in comment that - do you understand why these methods are not thread-safe if called from multiple threads?我在评论中问你问题 -你明白为什么如果从多个线程调用这些方法不是线程安全的吗? and you pointed me to a link without specifying that if you really understood it or not and why do you think that your class is not thread safe so I am providing a little bit of background instead of directly answering the question.你给我指了一个链接,但没有说明你是否真的理解它,为什么你认为你的类不是线程安全的,所以我提供了一些背景知识,而不是直接回答这个问题。

A Bit of Short Discussion一些简短的讨论

Any class or its methods might become not thread safe when you start sharing data among runner / calling threads.当您开始在运行程序/调用线程之间共享数据时,任何类或其方法都可能变得不是线程安全的。 Your class by default is thread - safe if no data is shared among threads so easiest way to make your class thread - safe is to stop sharing data among threads and in your case, its going to be removal of - emap ( because its a class state and used in methods ) & List<List<String>> workers ( This is what I am not sure of since its a reference passed on from caller and different method calls will be working on same instance or might be different instances are passed to this method ) and replace these by method local variables.默认情况下,您的类是线程安全的 - 如果线程之间没有共享数据,那么使您的类成为线程的最简单方法是停止在线程之间共享数据,在您的情况下,它将被删除 - emap (因为它是一个类状态并在方法中使用)& List<List<String>> workers (这是我不确定的,因为它是从调用者传递的引用,并且不同的方法调用将在同一实例上工作,或者可能将不同的实例传递给此方法)并用方法局部变量替换这些。

Method local variables are thread - safe by default since new instances are created and destroyed for each call.方法局部变量默认是线程安全的,因为每次调用都会创建和销毁新实例。

if you can't do that or not feasible , follow oleg.cherednik's answer to synchronize for variable - emap - either at block level or method level.如果您不能这样做或不可行,请按照 oleg.cherednik 的答案在块级别或方法级别同步变量 - emap Do remember that there are various ways to synchronize in Java with synchronized keyword being easiest.请记住,在 Java 中有多种同步方法,其中synchronized关键字是最简单的。

Now for method parameters - List<List<String>> workers & int eid , synchronization for eid is not needed since you are simply reading it and not updating & also its not pass by reference but pass by value due to type being primitive.现在的方法参数- List<List<String>> workersint eid ,同步eid没有必要的,因为你只是读它,而不是更新和也它不是按引用传递,但是传值因类型而原始。

Synchronization for access to List<List<String>> workers is needed if you are passing same list instance to calls of this method from different threads.如果您将相同的列表实例传递给来自不同线程的此方法的调用,则需要同步访问List<List<String>> workers Refer to Gray's Answer - Here and this point is missed in oleg.cherednik's answer.请参阅Gray 的回答 -在 oleg.cherednik 的回答中忽略了这一点。 You are better judge if synchronization would be needed or not for this reference.您最好判断此参考是否需要同步。

Its easy to assume that List iteration is thread- safe ( since you are not updating the list ) but that might not always be true .很容易假设List迭代是线程安全的(因为您没有更新列表),但这可能并不总是正确的。 Refer this question and all answers for detailed discussion. 请参阅此问题和所有答案以进行详细讨论。

So summary is this - you start implementing thread - safety for your class by first analyzing if some objects are shared among threads or not.所以总结是这样的——你开始为你的类实现线程安全,首先分析一些对象是否在线程之间共享。 If objects are shared , read / write to those objects need to be synchronized ( to make it atomic & provided those objects are not already thread - safe ) .如果对象是共享的,则对这些对象的读/写需要同步(以使其具有原子性,前提是这些对象还不是线程安全的)。 If no objects are shared - its already thread safe .如果没有共享对象 - 它已经是线程安全的。 Also, try to create your classes with already thread - safe data structures , that way you will have less work to do.此外,尝试使用线程安全的数据结构创建类,这样您的工作量就会减少。

java.lang.NullPointerException ( NPE ) point of oleg.cherednik's answer stands too. oleg.cherednik 的答案的java.lang.NullPointerException ( NPE ) 点也是如此。

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

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