Clojure, Java, and Sleeping Barbers
Join the DZone community and get the full member experience.
Join For FreeMy friend Matt wrote a pretty rad (yep, I used that word) implementation of the “sleeping barber” program in Clojure. Matt’s code had an almost sentence-like simplicity to it – pithy but expressive — that impressed me.
As we walked through how the program worked, I couldn’t help but wonder about a Java implementation. So, I wrote one.
package name.christianson.mike; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import static java.util.concurrent.TimeUnit.*; public class BarberShop { public static final int NUM_WAITING_ROOM_CHAIRS = 3; public static final long SHOP_RUNTIME_MILLIS = SECONDS.toMillis(10); private final static AtomicBoolean shopOpen = new AtomicBoolean(); private final static AtomicInteger totalHaircuts = new AtomicInteger(); private final static AtomicInteger lostCustomers = new AtomicInteger(); private final BlockingQueue<Object> waitingRoom = new LinkedBlockingQueue<>(NUM_WAITING_ROOM_CHAIRS); public static void main(String[] args) throws InterruptedException { BarberShop shop = new BarberShop(); ExecutorService executor = Executors.newFixedThreadPool(3); Runnable customerGenerator = new CustomerGenerator(shop); Runnable barber = new Barber(shop); Runnable progressTracker = new ProgressTracker(shop); shop.open(); executor.execute(progressTracker); executor.execute(barber); executor.execute(customerGenerator); executor.shutdown(); Thread.sleep(SHOP_RUNTIME_MILLIS); shop.close(); } private void close() { shopOpen.set(false); } private void open() { shopOpen.set(true); } public boolean isOpen() { return shopOpen.get(); } public boolean seatCustomerInWaitingRoom(Object customer) { boolean customerSeated = waitingRoom.offer(customer); if(!customerSeated) { lostCustomers.incrementAndGet(); } return customerSeated; } public Object napUntilCustomerArrives() throws InterruptedException { return waitingRoom.take(); } public void recordHaircut() { totalHaircuts.incrementAndGet(); } public Object lostCustomers() { return lostCustomers.get(); } public Object haircuts() { return totalHaircuts.get(); } }
Matt’s is self-contained in one file while mine is split across multiple files. (I opted to not use anonymous/inner classes.) I think we were a bit surprised that the concurrency logic is similar and the ”main” driving section of each implementation follows the same set-up procedure. Perhaps my code was influenced by way of transliteration?
I’m struck by how Matt’s Clojure programs reads somewhat like a story while my Java program reads like instructions for a computer.
Published at DZone with permission of Mike Christianson, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments