在遥远的冰雪王国里,雪堆像钻石一样闪闪发光,星星低语着童话故事,圣诞老人正在为一年中最神奇的夜晚做准备。他的工厂像一架巨大的乐器一样嗡嗡作响:精灵们拿着盒子跑来跑去,玩具闪闪发光,每一件新的现成礼物都敲响了铃声。
但是魔法受到了威胁。
“玩具太多!饲料已满!” ——精灵首席制作人抱怨道。
“我们没时间收拾行李!” - 包装精灵附和着他。
圣诞老人想:“我怎样才能帮助我的精灵呢?他们已经尽力了,但他们离不开魔法。”
圣诞老人求助于一种名为“同步”的咒语。它创造了一个保护屏障,这样精灵们在使用普通胶带时就不会互相推挤和困惑。
“现在一次只有一个人可以放下或拿起玩具,”圣诞老人解释道。
这就是它的样子:
class SantaFactory { private final Queue<String> conveyorBelt = new LinkedList<>(); private final int MAX_CAPACITY = 10; public void produce(String toy) throws InterruptedException { synchronized (conveyorBelt) { while (conveyorBelt.size() == MAX_CAPACITY) { System.out.println("Производитель ждёт: лента заполнена!"); conveyorBelt.wait(); // Производитель ждёт, пока появится место } conveyorBelt.add(toy); System.out.println("Игрушка произведена: " + toy); conveyorBelt.notifyAll(); // Уведомляем упаковщиков о новой игрушке } } public void consume() throws InterruptedException { synchronized (conveyorBelt) { while (conveyorBelt.isEmpty()) { System.out.println("Потребитель ждёт: игрушек нет!"); conveyorBelt.wait(); // Упаковщик ждёт, пока появится игрушка } String toy = conveyorBelt.poll(); System.out.println("Игрушка упакована: " + toy); conveyorBelt.notifyAll(); // Уведомляем производителей о свободном месте } } }
wait和notifyAll的神奇属性:
wait():使线程休眠,直到某个条件(例如空磁带)变为 false。
notifyAll():唤醒所有等待线程,检查它们是否可以继续。
圣诞老人意识到精灵们经常忘记调用notifyAll,这造成了延迟。然后他使用了一个神奇的工具——BlockingQueue,它本身就负责处理线程。
BlockingQueue 执行以下操作:
如果磁带已满,制造商会自动等待。
如果磁带是空的,打包者自己就会明白他需要等待。
class SantaFactory { private final Queue<String> conveyorBelt = new LinkedList<>(); private final int MAX_CAPACITY = 10; public void produce(String toy) throws InterruptedException { synchronized (conveyorBelt) { while (conveyorBelt.size() == MAX_CAPACITY) { System.out.println("Производитель ждёт: лента заполнена!"); conveyorBelt.wait(); // Производитель ждёт, пока появится место } conveyorBelt.add(toy); System.out.println("Игрушка произведена: " + toy); conveyorBelt.notifyAll(); // Уведомляем упаковщиков о новой игрушке } } public void consume() throws InterruptedException { synchronized (conveyorBelt) { while (conveyorBelt.isEmpty()) { System.out.println("Потребитель ждёт: игрушек нет!"); conveyorBelt.wait(); // Упаковщик ждёт, пока появится игрушка } String toy = conveyorBelt.poll(); System.out.println("Игрушка упакована: " + toy); conveyorBelt.notifyAll(); // Уведомляем производителей о свободном месте } } }
为了让精灵们不累,圣诞老人创造了一个神奇的工具——线程池。现在每个精灵各司其职,数量也自动调节。
“精灵们不会再互相追赶了,一切都很顺利。”圣诞老人高兴地说。
代码示例:
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; class SantaFactoryBlocking { private final BlockingQueue<String> conveyorBelt = new ArrayBlockingQueue<>(10); public void produce(String toy) throws InterruptedException { conveyorBelt.put(toy); // Если лента заполнена, поток автоматически ждёт System.out.println("Игрушка произведена: " + toy); } public void consume() throws InterruptedException { String toy = conveyorBelt.take(); // Если лента пуста, поток автоматически ждёт System.out.println("Игрушка упакована: " + toy); } }
newFixedThreadPool(n):创建一个将被重用的 n 个线程池。
提交(任务):在其中一个线程中启动一项任务。
shutdown():所有任务完成后停止执行。
在最后阶段,圣诞老人添加了一点额外的魔法:现在精灵们异步工作,这加快了进程。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SantaRaceWithExecutors { public static void main(String[] args) { SantaFactoryBlocking factory = new SantaFactoryBlocking(); ExecutorService executor = Executors.newFixedThreadPool(4); // 4 эльфа // Запускаем 2 производителя for (int i = 1; i <= 2; i++) { executor.submit(() -> { try { for (int j = 1; j <= 20; j++) { factory.produce("Игрушка #" + j); Thread.sleep(100); // Производство занимает время } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } // Запускаем 2 упаковщика for (int i = 1; i <= 2; i++) { executor.submit(() -> { try { for (int j = 1; j <= 20; j++) { factory.consume(); Thread.sleep(150); // Упаковка занимает время } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } executor.shutdown(); // Завершаем работу после выполнения всех задач } }
异步:任务在后台线程中执行,不会阻塞主线程。
易于使用:无需手动管理线程。
当最后一个玩具装完后,圣诞老人高兴地叹了口气。 “精灵们,你们做了一件了不起的工作。多线程的魔力让我们不仅更快,而且更快乐!”
现在,在除夕夜的每个晚上,圣诞老人都会向他的助手讲述一个关于多线程如何拯救节日的童话故事。
✨ 朋友们,新年快乐! ?
以上是圣诞老人的节日竞赛:Java 多线程的魔力的详细内容。更多信息请关注PHP中文网其他相关文章!