Как синхронизировать выполнение двух методов в Java? [Дубликат]

Вместо длинного href используйте link[href*="style.css"], чтобы найти style.css

var click = false;
var path = '/rip-access/wp-content/themes/RIP/assets/css/';

$('#css_toggle').on('click', function() {
  if (!click) {
    $('link[href*="style.css"]').attr('href', path + 'style1.css');
    click = true;
    console.log('changed to style1.css');
  } else {
    $('link[href*="style1.css"]').attr('href', path + 'style.css');
    click = false;
    console.log('changed to style.css');
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="css_toggle" title="I'm a tooltip!">Toggle</button>
<link href="/rip-access/wp-content/themes/RIP/assets/css/style.css" rel="stylesheet" />

А также вы можете использовать ID вместо выбора по имени файла.

$('#css') // jquery selector

<link id="css" href="..." rel="stylesheet" /> // html
7
задан assylias 3 January 2013 в 09:42
поделиться

5 ответов

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

EDIT: Я действительно думаю, что вы пытаетесь создать проблему, которая по своей сути сложна (см. Второй-последний абзац ) и, вероятно, не нужен (см. последний абзац). Но это говорит о том, как это можно сделать, и я оставлю цветовой комментарий для конца этого ответа.

private int someMethod1Invocations = 0;
private int someMethod2Invocations = 0;

public void someMethod1() {
    synchronized(this) {
        // Wait for there to be no someMethod2 invocations -- but
        // don't wait on any someMethod1 invocations.
        // Once all someMethod2s are done, increment someMethod1Invocations
        // to signify that we're running, and proceed
        while (someMethod2Invocations > 0)
            wait();
        someMethod1Invocations++;
    }

    // your code here

    synchronized (this) {
        // We're done with this method, so decrement someMethod1Invocations
        // and wake up any threads that were waiting for that to hit 0.
        someMethod1Invocations--;
        notifyAll();
    }
}

public void someMethod2() {
    // comments are all ditto the above
    synchronized(this) {
        while (someMethod1Invocations > 0)
            wait();
        someMethod2Invocations++;
    }

    // your code here
    synchronized(this) {
        someMethod2Invocations--;
        notifyAll();
    }
}

Одна вопиющая проблема с вышеизложенным заключается в том, что она может приводят к голоданию нити . Например, someMethod1() работает (и блокирует someMethod2() s), и так же, как он собирается закончить, появляется еще один поток и вызывает someMethod1(). Это происходит очень хорошо, и так же, как он заканчивает , начинается другая нить someMethod1() и т. Д. В этом случае someMethod2() никогда не будет иметь возможности запускать. На самом деле это не ошибка в приведенном выше коде; это проблема с вашими потребностями в дизайне, которые должны активно работать над решением. Я думаю, что справедливый AbstractQueuedSynchronizer мог бы сделать трюк, хотя это упражнение осталось читателю. :)

Наконец, я не могу устоять, но вставить недоразумение: учитывая, что операции ConcurrentHashMap довольно быстро прокручиваются, вам может быть лучше просто поставить один мьютекс вокруг обоих методов и просто сделать с этим. Итак, да, потоки должны будут стоять в очереди, чтобы вызвать someMethod1(), но каждый поток завершит свою очередь (и, таким образом, позволит другим потокам продолжить) чрезвычайно быстро. Это не должно быть проблемой.

4
ответ дан yshavit 28 August 2018 в 13:38
поделиться

Возможно, это не сработает (см. комментарии) - оставив его для информации.


Один из способов - использовать Семафоры :

  • один семафор sem1 с одним разрешением, связанным с методом 1
  • одним семафором sem2 с одним разрешением, связанным с методом2

при вводе method1, попробуйте получить разрешение sem2 и, если доступно, немедленно отпустите его.

См. этот пост для примера реализации.

Примечание: в вашем коде, даже если ConcurrentMap является потокобезопасным, операция 1 и операция 2 (например) не являются атомарными, поэтому в вашем сценарии возможно следующее чередование:

  • Thread 1 запускает операцию 1
  • Резьба 2 работает 1
  • Резьба 2 работает 2
  • Резьба 1 запускает операцию 2
2
ответ дан 3 revs 28 August 2018 в 13:38
поделиться

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

public class TrafficLight<T> {

    private final int maxSequence;
    private final ReentrantLock lock = new ReentrantLock(true);
    private final Condition allClear = lock.newCondition();
    private int registered;
    private int leftInSequence;
    private T openState;

    public TrafficLight(int maxSequence) {
        this.maxSequence = maxSequence;
    }

    public void acquire(T state) throws InterruptedException {
        lock.lock();
        try {
            while ((this.openState != null && !this.openState.equals(state)) || leftInSequence == maxSequence) {
                allClear.await();
            }
            if (this.openState == null) {
                this.openState = state;
            }
            registered++;
            leftInSequence++;
        } finally {
            lock.unlock();
        }
    }

    public void release() {
        lock.lock();
        try {
            registered--;
            if (registered == 0) {
                openState = null;
                leftInSequence = 0;
                allClear.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }
}

acquire() будет блокироваться, если другое состояние активен, пока он не станет неактивным.

maxSequence помогает предотвратить потоковое голодание, позволяя передавать только максимальное количество потоков (тогда они должны будут стоять так же, как и остальные) , Вы можете сделать вариант, который использует временное окно.

Для вашей проблемы someMethod1() и someMethod2() вызовет метод получения () с другим состоянием в начале и release() в конце .

0
ответ дан bowmore 28 August 2018 в 13:38
поделиться
2
ответ дан Evgeniy Dorofeev 28 August 2018 в 13:38
поделиться

Прежде всего: ваша карта является потокобезопасной как ее ConcurrentMap. Это означает, что операции на этой карте, такие как add, содержат и т. Д., Являются потокобезопасными.

Secondaly Это не гарантирует, что даже ваши методы (somemethod1 и somemethod2) также являются потокобезопасными. Таким образом, ваши методы не являются взаимоисключающими, и два потока одновременно могут получить к ним доступ.

Теперь вы хотите, чтобы они были взаимно взаимными: один подход мог быть перенесен на все операции (операция 1, .. операция 4 ) в одном методе и на основе условия вызова каждого.

0
ответ дан rai.skumar 28 August 2018 в 13:38
поделиться