Вместо flexbox
я рекомендую использовать столбцы для таких сеток. Как вы можете видеть, расстояние на нижних изображениях может быть лучше, но для собственного решения для CSS я считаю, что это довольно аккуратно. Нет больше JS:
.container {
max-width: 900px;
width: 100%;
margin: 0 auto;
}
ul {
margin: 0;
padding: 0;
}
ul li {
list-style: none;
font-size: 0;
}
.portfolio ul {
-moz-column-count: 4;
-webkit-column-count: 4;
column-count: 4;
-moz-column-gap: 3px;
-webkit-column-gap: 3px;
column-gap: 3px;
}
.portfolio ul:hover img {
opacity: 0.3;
}
.portfolio ul:hover img:hover {
opacity: 1;
}
.portfolio ul li {
margin-bottom: 3px;
}
.portfolio ul li img {
max-width: 100%;
transition: 0.8s opacity;
}
Вы сами синхронизируете объект потока, что является неправильным использованием. Случается, что умирающий поток выполнения всегда вызывает notify
на свой объект Thread
: Thread.join
полагается на этот . Поэтому понятно, почему вы получаете то же поведение с вашим notify
и без него.
Решение: используйте отдельный объект для координации потоков; это стандартная практика.
У вас есть вложенные синхронизированные {} конструкции в двух местах. Эти конструкции кажутся чем-то странным: нить не реагирует на уведомления вообще и только возобновляется, когда ThreadB (b) завершается. Удалить это:
public class JavaApplication2 {
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
try {
System.out.println(" ### Waiting for notify");
synchronized (b) {
b.wait();
}
System.out.println(" ### Notified");
} catch (InterruptedException e) {
}
System.out.println("### Total is: " + b.total);
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
total += 1;
System.out.println(" *** Ready to notify in 5 secs");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(" *** Notification sent");
synchronized (this) {
notify();
}
System.out.println(" *** 5 sec post notification");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(" *** ThreadB exits");
}
}
Возможно, что код выше работает корректно: при уведомлении () текущий основной поток возобновляется через 5 секунд и до того, как мы увидим сообщение, которое ThreadB завершает. С notify () закомментировал, что основной поток возобновляется через 10 секунд и после сообщения о прекращении ThreadB, потому что notify () вызывается anywhay из другого кода. Марко Тополник объясняет, почему и откуда происходит этот вызов «за сценой» notify ().
notify
называется в любом случае, как я объясняю в своем ответе. Это не поддельное пробуждение.
– Marko Topolnik
7 January 2013 в 00:26
Вы не можете зависеть от того, не возвращаетесь ли вы от ожидания до уведомления: «возможны прерывания и ложные пробуждения». В общем случае вы должны завернуть вызов ожидания в цикле, пока поток должен продолжать ожидание.
Метод notifyAll()
вызывается для объекта Thread
конечной нити. Этот факт странно задокументирован в описании Thread.join
со следующим предложением:
По мере того, как поток завершается, этот метод this.notifyAll вызывается. Рекомендуется, чтобы приложения не использовали wait, notify или notifyAll для экземпляров Thread.
blockquote>Таким образом, если вы явно не читаете описание
join
, которое вы не обязательно придется, вы не узнаете причину странного поведения.
Если вы попытаетесь синхронизировать свой код с любым другим объектом, который ThreadB
вы обнаружите, что он никогда не заканчивается. Это потому, что есть скрытый вызов notify
.
Хотя я не знаю нигде, что это указано, Thread уведомляет себя, когда он заканчивается. Это подразумевается в способе реализации метода join
. Это код для join
:
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
(Из исходного кода JDK7)
Как вы можете видеть, вызовы wait
имеют смысл, если где-то там является вызовом notify
, который вызывается после окончания потока. Тот же вызов notify
позволяет завершить вашу программу.
Я делал то же тестирование на операции wait / notify при чтении OCP SE 7, хороший catch. Я думаю, мы должны позволить автору объяснить.
notify
, вызывается методthis.notifyAll
. – Eddie Jamsession 7 January 2013 в 00:22notify
совпадает сthis.notify
. – Marko Topolnik 7 January 2013 в 00:27notifyAll
не совпадает сnotify
. Это разные методы. – Eddie Jamsession 7 January 2013 в 00:28