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;
    }


}

Должен ли я использовать ключевое слово synchronized, чтобы сделать его потокобезопасным. Должен ли я использовать Vector и Hashtable, если метод синхронизирован.

В качестве альтернативы, что, если я использую вектор и Hashtable, переместите переменную emap в sortSalaries() и передайте ее в dfs(). Хорошо, если я не использую синхронизированное ключевое слово в этом случае ..

2
mzz 25 Окт 2018 в 05:34

2 ответа

Лучший ответ

Я задал вам вопрос в комментарии: понимаете ли вы, почему эти методы не являются потокобезопасными, если вызываются из нескольких потоков? и вы указали мне ссылку, не указав, действительно ли вы это поняли или нет, и почему вы думаете, что ваш класс не является потокобезопасным, поэтому я предлагаю немного предыстории вместо того, чтобы напрямую отвечать на вопрос.

Короткое обсуждение

Любой класс или его методы могут стать небезопасными для потоков, когда вы начинаете делиться данными между исполняющими / вызывающими потоками. Ваш класс по умолчанию является потокобезопасным, если никакие данные не используются совместно между потоками, поэтому самый простой способ сделать ваш класс потокобезопасным - это прекратить совместное использование данных между потоками, и в вашем случае это будет удаление - emap (потому что это состояние класса и используется в методах) & List<List<String>> workers (это то, в чем я не уверен, так как это ссылка, переданная от вызывающего, и разные вызовы методов будут работать с одним и тем же экземпляром или этому методу могут быть переданы другие экземпляры) и заменить их локальными переменными метода.

Локальные переменные метода по умолчанию потокобезопасны, поскольку новые экземпляры создаются и уничтожаются при каждом вызове.

Если вы не можете это сделать или это невозможно, следуйте ответу oleg.cherednik для синхронизации для переменной - emap - либо на уровне блока, либо на уровне метода. Помните, что в Java есть различные способы синхронизации, причем ключевое слово synchronized проще всего.

Теперь для параметров метода - List<List<String>> workers и int eid, синхронизация для eid не требуется, так как вы просто читаете его, а не обновляете, а также его не передают по ссылке, а по значению из-за типа быть примитивным.

Синхронизация для доступа к List<List<String>> workers необходима, если вы передаете один и тот же экземпляр списка вызовам этого метода из разных потоков. Обратитесь к Ответу Грея - здесь, и этот момент отсутствует в ответе oleg.cherednik. Вам лучше судить, потребуется ли синхронизация для этой ссылки.

Легко предположить, что итерация List является поточно-ориентированной (поскольку вы не обновляете список), но это не всегда может быть правдой. См. этот вопрос и все ответы для подробного обсуждения.

Итак, итоги таковы - вы начинаете реализовывать потокобезопасность для своего класса, сначала анализируя, являются ли некоторые объекты общими для потоков или нет. Если объекты являются общими, чтение / запись для этих объектов необходимо синхронизировать (чтобы сделать их атомарными и при условии, что эти объекты еще не являются потокобезопасными). Если нет общих объектов - это уже потокобезопасный. Кроме того, попробуйте создать свои классы с уже потокобезопасными структурами данных, так у вас будет меньше работы.

java.lang.NullPointerException (NPE) пункт ответа oleg.cherednik тоже стоит.

1
Sabir Khan 25 Окт 2018 в 08:20
  1. Защитите emap от внешнего доступа
  2. Инициируйте emap, чтобы исключить NPE

Примере:

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
    }
}

В sortSalaries вы можете минимизировать блок synchoronized с помощью for loop. В dfs вы получаете доступ к emap в разных местах метода, и поэтому вам нужно синхронизировать метод enire.

Использование ConcurrentHashMap или Vector здесь не помогает, потому что между элементами get/set в коллекции они могут быть изменены, что не подходит для метода dfs: он должен зависнуть emap, когда он называется.

1
oleg.cherednik 25 Окт 2018 в 04:56