Я пытаюсь понять, как реализовать потоки, оспаривающие глобальные переменные. В моей реализации я создал 2 переменные и хочу, чтобы 4 Threds (например) оспаривали их путем уменьшения.
Первая проблема заключается в том, что способ, которым я реализовал потребление, всегда будет следовать порядку (первый поток уменьшает хлопьевидное мороженое, а второй поток уменьшает шоколадное мороженое).
Есть ли способ улучшить это правило?
И я бы не хотел знать, где лучше всего использовать CountDownLatch.
public class IceCream implements Runnable {
private static int flake = 1;
private static int chocolate = 1;
@Override
public void run() {
buyIceCream();
}
private void synchronized buyIceCream() {
try {
if (IceCream.flake>0) {
System.out.println("");
System.out.println("successfully purchased " +Thread.currentThread().getName());
Thread.sleep(200);
IceCream.flake--;
System.out.println("");
}
else if (IceCream.chocolate>0) {
System.out.println("");
System.out.println("successfully purchased " +Thread.currentThread().getName());
Thread.sleep(200);
IceCream.chocolate--;
System.out.println("");
}
else {
System.out.println("No more ice cream " +Thread.currentThread().getName());
}
}
catch(Exception e) {
}
}
}
public static void main(String[] args) throws InterruptedException {
IceCream c = new IceCream();
Thread[] t = new Thread[4];
for(int i = 0; i<t.length; i++) {
t[i] = new Thread(c);
t[i].setName("Kid"+ i);
t[i].start();
t[i].join();
}
}
Улучшите способ, которым Поток «покупает» хлопьевидное мороженое и покупает шоколадное мороженое. И правильное слово было не в лучшем месте, а в правильном. Потому что я хотел, чтобы все потоки запускались одновременно. И я не знаю, использую ли я CountDownLatch в основном или в своем классе IceCream.
Executors.invokeAll
отправит кучу задач примерно в одно и то же время, но не точно одновременно. Вы не можете точно контролировать, когда выполняются потоки, не используя обычное программирование (Java или что-то другое) на обычном оборудовании с обычными операционными системами. См. вычисления в реальном времени и Java в реальном времени.
Это ошибка:
t[i].start();
t[i].join();
Вызов join()
не возвращается до тех пор, пока поток не завершится, поэтому ваша программа никогда не позволит запускать более одного потока одновременно. Вы можете исправить ошибку, написав два отдельных цикла. Первый создает и запускает все потоки, а затем второй объединяет их все.
for(int i = 0; i<t.length; i++) {
t[i] = new Thread(c);
t[i].setName("Kid"+ i);
t[i].start();
}
for(int i = 0; i<t.length; i++) {
t[i].join();
}
Это еще одна ошибка:
public void run() {
buyIceCream();
}
private void synchronized buyIceCream() {
...
}
Обертывание всего, что делает поток, внутри одного метода synchronized
— это еще один способ гарантировать, что никакие два ваших потока не будут запущены одновременно.
По крайней мере, вы должны удалить вызовы sleep()
из блока synchronized
:
private void buyIceCream() {
String message = "No more ice cream ";
synchronized (this) {
if (IceCream.flake>0) {
IceCream.flake--;
message = "Ice cream flake purchased by" + Thread.currentThread().getName();
}
else if (IceCream.chocolate>0) {
IceCream.chocolate--;
message = "Chocolate ice cream purchased by" + Thread.currentThread().getName();
}
}
System.out.println(message);
try {
Thread.sleep(200);
}
catch(Exception e) {
System.out.println("Never, EVER, completely ignore an exception.");
}
}
Я также переместил вызов System.out.println()
из блока synchronized
, потому что знаю, что символы, напечатанные любым вызовом Один, не будут чередоваться с символами, напечатанными одним вызовом из другого потока. (См. https://stackoverflow.com/a/9459743/801894)
В логике sysout, которую вы сделали, могу ли я захватить sysout для каждого мороженого? Пример: System. out.println("Ice cream flake purchased by" + Thread.currentThread().getName());
и System. out.println("Chocolate ice cream purchased by" + Thread.currentThread().getName());
@billy_ta, смотрите мой обновленный (упрощенный!) ответ выше.
Ваш вопрос не ясен. Какова общая цель вашего эксперимента? Что именно означает «улучшить это правило»? Что касается «лучшего места для использования CountDownLatch», для чего нужна защелка и по каким критериям мы оцениваем «лучшее» место?