Это ожидаемый результат с синхронизацией метода - PullRequest
0 голосов
/ 30 апреля 2020

Итак, у меня есть этот метод:

public static synchronized int getFilesTaken() {
        int filesTaken = (int) Math.ceil(1.0 * filesLeft / threadsLeft);
        filesLeft -= filesTaken;
        threadsLeft--;
        fileIndex += filesTaken;
        return filesTaken;
    }

filesLeft, threadsLeft и fileIndex - все глобальные переменные, используемые для перебора глобальной File[]

Тогда у меня есть этот метод, который вызывается при запуске потока:

public static void parseFiles() {
        int filesTaken = (int) Math.ceil(filesLeft / threadsLeft);
        long a = System.currentTimeMillis();
        int fileIndexTemp = fileIndex;
        int filesTaken = getFilesTaken();
        System.out.println(fileIndexTemp);
        //rest of the implementation unimportant
}

Я думал, что синхронизация сделает это так, что только один поток сможет одновременно обращаться к глобальным переменным и изменять их. Тем не менее, строка печати печатает одни и те же числа в каждой нити. Если у меня есть 1000 filesLeft и 4 threadsLeft, fileIndexTemp, который начинается с 0 в начале программы, почти всегда печатает 0, иногда печатая 250, 500 или 750, вместо того, чтобы печатать 0, 250, 500 и 750.

Правильно ли я синхронизировал, и если нет, как я могу решить эту проблему?

1 Ответ

0 голосов
/ 30 апреля 2020

Синхронизированный метод установит блокировку на this при входе, поэтому другой поток не будет go в том же методе. Для метода stati c нет this, поэтому блокировка размещается в экземпляре Class. Поэтому, сделав getFilesTaken, все, что вы предотвратили, заключается в том, что только один поток может войти в getFilesTaken, и ничего более. Если многие потоки вызывают getFiltesTaken, все они будут выполняться одновременно, но они будут вызывать getFilesTaken один за другим.

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

Object lock=new Object();
...
public static void parseFiles() {
   synchronized(lock) {
     // Critical section
   }
}

Выше, только один поток сможет заблокировать lock объект в любой момент времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...