KarelWineProgram2 (KarelOOP2)
Retired DISLab
/* * Copyright 2020 Sangwon Park @ DISLab, HUFS * * 생산자, 소비자 프로그램으로서 lock을 이용하여 경쟁을 잘 쳐러하도록 한다. * 가운데 와인(비퍼)를 두고 경쟁하는 구도이다. * GoodConsumer는 와인을 마시려고 하고, * GoodProducer는 와인을 채우려고 한다. * 각 2개씩 총 4개의 스레드를 만들어 동작시킨다. * * 동작하는 알고리즘은 GoodGlass에 lock을 거는 것으로 한다. * 이때 lock을 걸지 못하는 원하는 상황이 될 때까지 wait(sleep) 한다. * wait을 하면 가지고 있던 lock을 푼다. 깨어날 때는 다시 lock을 획득한 상태가 된다. * 이때 중요한 점은 깨어났다고 해서 원하는 자원이 반드시 사용가능한 것은 아니라는 것이다. * 그러므로 깨어났을 때 검사해야 하는 것은 자원을 사용할 수 있는지 검사하는 것이다. * 이것은 프로그램이 sleep 하는 기간이 길어지는 것이 특징이다. */ package cp.java.week11.thread; import java.awt.Color; import acm.util.ErrorException; import hufs.dislab.karel.ColoredKarel; import hufs.dislab.karel.IKarel; import hufs.dislab.karel.IKarelProgram; class GoodGlass { private transient boolean isFilled = false; private int x, y; public GoodGlass(int x, int y) { this.x = x; this.y = y; } public synchronized Color drink(IKarel karel) { while (!isFilled) { try { this.wait(); } catch (InterruptedException e) { } } IKarelProgram program = IKarelProgram.getProgram(); Color color = program.getCornerColor(x, y); if (color == null) throw new ErrorException("와인이 없습니다."); program.setCornerColor(x, y, null); isFilled = false; this.notifyAll(); program.trace(); return color; } public synchronized void fill(IKarel karel, Color color) { while (isFilled) { try { this.wait(); } catch (InterruptedException e) { } } IKarelProgram program = IKarelProgram.getProgram(); if (program.getCornerColor(x, y) != null) throw new ErrorException("이미 채워져 있습니다."); program.setCornerColor(x, y, color); isFilled = true; this.notifyAll(); program.trace(); } } class GoodConsumer extends ColoredKarel { private GoodGlass glass; private int steps; public GoodConsumer(String name, GoodGlass glass, int steps) { super(name, null); this.glass = glass; this.steps = steps; } @Override public void run() { while (true) { move(steps); Color color = glass.drink(this); // DRINK setColor(color); turnAround(); move(steps); setColor(null); turnAround(); } } } class GoodProducer extends ColoredKarel { private GoodGlass glass; private int steps; private Color color; public GoodProducer(String name, Color color, GoodGlass glass, int steps) { super(name, color); this.glass = glass; this.steps = steps; this.color = color; } @Override public void run() { while (true) { move(steps); glass.fill(this, color); // FILL setColor(null); turnAround(); move(steps); setColor(color); turnAround(); } } } /** * * @author Sangwon Park * @since KarelOOP 2 (2020.10.1) */ @SuppressWarnings("serial") public class KarelWineProgram2 extends IKarelProgram { @Override protected void onInit() { int centerX = getWorldWidth() / 2; int centerY = getWorldHeight() / 2; glass = new GoodGlass(centerX, centerY); IKarel karel = new GoodConsumer("C1", glass, STEP1); addIKarel(karel, centerX - 1 - STEP1, centerY, EAST, 0); threads[0] = new Thread(karel); karel = new GoodProducer("P1", RED, glass, STEP1); addIKarel(karel, centerX, centerY - 1 - STEP1, NORTH, 0); threads[1] = new Thread(karel); karel = new GoodConsumer("C2", glass, STEP2); addIKarel(karel, centerX + 1 + STEP2, centerY, WEST, 0); threads[2] = new Thread(karel); karel = new GoodProducer("P2", PINK, glass, STEP2); addIKarel(karel, centerX, centerY + 1 + STEP2, SOUTH, 0); threads[3] = new Thread(karel); } @Override protected void onStart() { for (Thread th : threads) th.start(); } public static void main(String[] args) { IKarelProgram.main(args, null); } private static final int STEP1 = 1; private static final int STEP2 = 2; Thread[] threads = new Thread[4]; GoodGlass glass; }