Вместо длинного 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
Я попробовал пару попыток с конструкциями более высокого уровня, но ничего не пришло в голову. Я думаю, что это может быть поводом для перехода к 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()
, но каждый поток завершит свою очередь (и, таким образом, позволит другим потокам продолжить) чрезвычайно быстро. Это не должно быть проблемой.
Возможно, это не сработает (см. комментарии) - оставив его для информации.
Один из способов - использовать Семафоры :
sem1
с одним разрешением, связанным с методом 1 sem2
с одним разрешением, связанным с методом2 при вводе method1, попробуйте получить разрешение sem2 и, если доступно, немедленно отпустите его.
См. этот пост для примера реализации.
Примечание: в вашем коде, даже если ConcurrentMap является потокобезопасным, операция 1 и операция 2 (например) не являются атомарными, поэтому в вашем сценарии возможно следующее чередование:
Я думаю, вы не можете сделать это без специального синхронизатора. Я взломал это, я назвал его 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()
в конце .
Прежде всего: ваша карта является потокобезопасной как ее ConcurrentMap. Это означает, что операции на этой карте, такие как add, содержат и т. Д., Являются потокобезопасными.
Secondaly Это не гарантирует, что даже ваши методы (somemethod1 и somemethod2) также являются потокобезопасными. Таким образом, ваши методы не являются взаимоисключающими, и два потока одновременно могут получить к ним доступ.
Теперь вы хотите, чтобы они были взаимно взаимными: один подход мог быть перенесен на все операции (операция 1, .. операция 4 ) в одном методе и на основе условия вызова каждого.