diff --git a/src/exercises/ex_z4/AuctionMain.java b/src/exercises/ex_z4/AuctionMain.java index 3e4da88..ab7a924 100644 --- a/src/exercises/ex_z4/AuctionMain.java +++ b/src/exercises/ex_z4/AuctionMain.java @@ -1,5 +1,6 @@ package exercises.ex_z4; +import java.util.ArrayList; import java.util.Arrays; @@ -16,10 +17,8 @@ public class AuctionMain { }; public static void main(String[] args) { - Auctioneer auctioneer = new Auctioneer("Paul", Arrays.asList(items)); - + Auctioneer auctioneer = new Auctioneer("Paul", new ArrayList(Arrays.stream(items).toList())); new Thread(auctioneer).start(); - for (int i = 0; i < names.length; i++) { new Thread(new Bidder(names[i], auctioneer)).start(); } diff --git a/src/exercises/ex_z4/Auctioneer.java b/src/exercises/ex_z4/Auctioneer.java index 4f8d249..1fd4256 100644 --- a/src/exercises/ex_z4/Auctioneer.java +++ b/src/exercises/ex_z4/Auctioneer.java @@ -1,29 +1,48 @@ package exercises.ex_z4; -import java.util.List; +import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; - +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import static exercises.ex_z4.AuctionState.*; public class Auctioneer implements Runnable { - private String name; - private Queue bids = new ConcurrentLinkedQueue<>(); + private static final DecimalFormat df = new DecimalFormat("#.00"); + + private final String name; + private final Queue bids = new ConcurrentLinkedQueue<>(); + private final ArrayList items; + private final Lock bidLock = new ReentrantLock(); + private final Condition bidCond = bidLock.newCondition(); + public final Lock stateLock = new ReentrantLock(); + public final Condition stateCond = stateLock.newCondition(); + private Bid maximumBid; private Thread countdownThread = null; - private boolean isAuctionActive = false; private AuctionState auctionState = PRESENTING_ITEM; - private final List items; - public Auctioneer(String name, List items) { + public Auctioneer(String name, ArrayList items) { this.name = name; this.items = items; } private void announce(String msg) { - System.out.println("[Auctioneer] " + msg); + System.out.println("[Auctioneer " + name + "] " + msg); + } + + private void setState(AuctionState newState) { + stateLock.lock(); + try { + auctionState = newState; + stateCond.signalAll(); + } finally { + stateLock.unlock(); + } } public void presentItem() throws InterruptedException { @@ -32,15 +51,21 @@ public class Auctioneer implements Runnable { announce("Get ready to bid..."); Thread.sleep(2000); announce("Bidding open !"); - auctionState = BIDDING; + maximumBid = null; + setState(BIDDING); } public void placeBid(Bid bid) { if (auctionState == BIDDING) { - System.out.println(bid.bidder() + " bids $" + bid.amount()); - bids.add(bid); + System.out.println(bid.bidder() + " bids $" + df.format(bid.amount())); + bidLock.lock(); + try { + bids.add(bid); + bidCond.signalAll(); + } finally { + bidLock.unlock(); + } } - notify(); } private void countdown() { @@ -52,8 +77,13 @@ public class Auctioneer implements Runnable { Thread.sleep(1000); System.out.println("One"); Thread.sleep(1000); - auctionState = SOLD; - notify(); + setState(SOLD); + bidLock.lock(); + try { + bidCond.signalAll(); + } finally { + bidLock.unlock(); + } } catch (InterruptedException _) {} } @@ -71,15 +101,19 @@ public class Auctioneer implements Runnable { } public void finalizeBidding() throws InterruptedException { - announce("And sold for $" + maximumBid.amount() + " !"); - Item item = items.removeFirst(); - announce(maximumBid.bidder() + " is now the proud owner of " + item); - maximumBid.bidder().addItem(item); + if (maximumBid == null) { + announce("Nobody wants this items ?!"); + } else { + announce("And sold for $" + df.format(maximumBid.amount()) + " !"); + Item item = items.removeFirst(); + announce(maximumBid.bidder() + " is now the proud owner of " + item); + maximumBid.bidder().addItem(item); + } Thread.sleep(2000); if (items.isEmpty()) { - auctionState = FINISHED; + setState(FINISHED); } else { - auctionState = PRESENTING_ITEM; + setState(PRESENTING_ITEM); } } @@ -94,12 +128,22 @@ public class Auctioneer implements Runnable { case BIDDING -> { Bid current_bid = bids.poll(); if (current_bid == null) { - startCountdown(); - wait(); + if (maximumBid != null) { + startCountdown(); + } + bidLock.lock(); + try { + bidCond.await(); + } finally { + bidLock.unlock(); + } + if (countdownThread != null) { + countdownThread.interrupt(); + } } else { - if (current_bid.amount() > maximumBid.amount()) { + if (maximumBid == null || current_bid.amount() > maximumBid.amount()) { maximumBid = current_bid; - announce("New best bid : " + maximumBid.amount() + " by " + maximumBid.bidder()); + announce("New best bid : " + df.format(maximumBid.amount()) + " by " + maximumBid.bidder()); } } } diff --git a/src/exercises/ex_z4/Bidder.java b/src/exercises/ex_z4/Bidder.java index a4a8e5c..e1b67a0 100644 --- a/src/exercises/ex_z4/Bidder.java +++ b/src/exercises/ex_z4/Bidder.java @@ -30,16 +30,27 @@ public class Bidder implements Runnable { if (state == BIDDING) { Random rand = new Random(); double addon = rand.nextDouble(500); - double base = auctioneer.getMaximumBid().amount(); + Bid maximumBid = auctioneer.getMaximumBid(); + double base = maximumBid == null ? 0 : maximumBid.amount(); lastBid = base + addon; auctioneer.placeBid(new Bid(this, lastBid)); + long minSleep = (long) (base * 10); try { - Utils.randomSleep(100, 5000); + Utils.randomSleep(minSleep, minSleep + 1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } else if (state == FINISHED) { break; + } else { + auctioneer.stateLock.lock(); + try { + auctioneer.stateCond.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + auctioneer.stateLock.unlock(); + } } } }