Блокировка потоков, только если доступ к тому же методу того же объекта - PullRequest
0 голосов
/ 25 мая 2018

У меня есть Объект с общими методами моего проекта с многопоточностью.Некоторые методы синхронизированы.Моя проблема - когда один из потоков обращается к методу синхронизации, а другой - к другому методу синхронизации.Это заставит один из потоков ждать другого.Я хочу заблокировать потоки только в случае доступа к тому же методу синхронизации, но я не знаю как.Недавно я обнаружил, что ключевое слово синхронизировано.

Вот один из моих методов.

public synchronized static void writeError(Exception err){

    String time = longDate();//here will get personalized current date
                             //longDate is not synchronized.

    try {

        FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);

        err.printStackTrace(new PrintWriter(path));

        path.flush();

    } catch (IOException e) {}

}

Есть идеи для этого метода?

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Так что synchronized всегда нужен объект для работы.Все synchronized блоки, которые совместно используют один и тот же объект, являются взаимоисключающими (т.е. только один поток может войти в блок за один раз).Помещение synchronized в объявление метода - это сокращение, например, методы равны synchronized(this), а статические методы - synchronized(Foo.class) (где Foo - класс, содержащий статический метод).

Зная этоВы можете легко создать несколько объектов для синхронизации, контролируя, какие методы могут быть запущены одновременно, а какие нет.

Пример класса, который позволяет запускать method3 одновременно с method1 или method2,но method1 и method2 являются взаимоисключающими.Кроме того, только один поток может запускать каждый метод одновременно.

public class Foo {
    private final static Object lock1 = new Object();
    private final static Object lock2 = new Object();

    public static void method1() {
        synchronized(lock1) {
            ...
        }
    }

    public static void method2() {
        synchronized(lock1) {
            ...
        }
    }

    public static void method3() {
        synchronized(lock2) {
            ...
        }
    }
}

Обратите также внимание на статический и нестатический.Здесь методы статические, а блокировки статические, так что все хорошо.Если бы методы были нестатичными, это предотвратило бы вызов методов также для разных объектов, это может быть не то, что вам нужно.В этом случае если сделать блокировки нестатичными, каждый экземпляр Foo будет работать, как описано ранее, но в случае foo1.method1() и foo2.method2() блокировки не будет, поскольку они не будут синхронизироваться на одном и том же объекте..

Как показывает ответ Шубхам Кадлаг, synchronized далеко не единственный инструмент параллелизма, который есть в Java.Пакет java.util.concurrent.locks имеет классы для блокировки (тогда как synchronized является встроенным механизмом).Например, ReentrantReadWriteLock позволяет вам обрабатывать ситуации, когда несколько потоков могут что-то делать (читать) одновременно, но только одному потоку разрешено выполнять операцию модификации (записи) одновременно.Они также позволяют вам установить тайм-аут на блокировку, тогда как synchronized будет радостно ждать вечно (не то, что tryLock() часто требуется, так как это ошибка программирования, если вы получаете взаимоблокировки).

Тогда выпоймите, что ручная блокировка для чурбанов в любом случае, и обнаружите, что java.util.concurrent имеет много классов, которые скрывают от вас блокировку и предлагают всевозможные расширенные функциональные возможности.

0 голосов
/ 25 мая 2018

Как упомянул Камаян, синхронизация на объектах будет соответствовать вашим потребностям.

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

См. https://dzone.com/articles/synchronized-vs-lock

Как указывалось в приведенном выше сообщении, синхронизация лучше всего подходит для небольшого числа потоков, получающих доступ к блокировке (<4), а блокировка может быть оптимальной для большого числа потоков, обращающихся к одним и тем же блокировкам. </p>

Вы можете ссылаться http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/ на различные примеры блокировок.

Создать отдельную блокировку для всех методов, как показано ниже.

private static ReentrantLock writeErrorlock = new ReentrantLock();

        public static void writeError(Exception err){
            writeErrorlock.lock();
            String time = longDate();//here will get personalized current date
                                     //longDate is not synchronized.

            try {

                FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);

                err.printStackTrace(new PrintWriter(path));

                path.flush();

            } catch (IOException e) {

            }
            finally {
                writeErrorlock.unlock();
            }

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