Запускать темы одновременно и оспаривать глобальные переменные

Я пытаюсь понять, как реализовать потоки, оспаривающие глобальные переменные. В моей реализации я создал 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», для чего нужна защелка и по каким критериям мы оцениваем «лучшее» место?

Basil Bourque 18.03.2022 21:32

Улучшите способ, которым Поток «покупает» хлопьевидное мороженое и покупает шоколадное мороженое. И правильное слово было не в лучшем месте, а в правильном. Потому что я хотел, чтобы все потоки запускались одновременно. И я не знаю, использую ли я CountDownLatch в основном или в своем классе IceCream.

billy_ta 18.03.2022 21:40
Executors.invokeAll отправит кучу задач примерно в одно и то же время, но не точно одновременно. Вы не можете точно контролировать, когда выполняются потоки, не используя обычное программирование (Java или что-то другое) на обычном оборудовании с обычными операционными системами. См. вычисления в реальном времени и Java в реальном времени.
Basil Bourque 18.03.2022 21:47
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
42
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это ошибка:

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 18.03.2022 22:54

@billy_ta, смотрите мой обновленный (упрощенный!) ответ выше.

Solomon Slow 19.03.2022 18:17

Другие вопросы по теме