/* From http://java.sun.com/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class DiningPhilosophers extends javax.swing.JApplet implements
ActionListener, ChangeListener {
private JButton stopStartButton = new JButton("start");
// delays can go from 0 to 10,000 milliseconds, initial value is 500
int grabDelay = 500;
private JSlider grabDelaySlider = new JSlider(JSlider.HORIZONTAL, 0, 100, 5);
private JLabel label = new JLabel(" 500 milliseconds");
private JPanel philosopherArea;
public ImageIcon[] imgs = new ImageIcon[3];
Chopstick[] chopsticks = new Chopstick[NUMPHILS];
String[] names = { "Arisduktle", "Dukrates", "Pythagoduke", "Duko",
"Dukimedes" };
static final int NUMPHILS = 5;
static final int HUNGRYDUKE = 0;
static final int RIGHTSPOONDUKE = 1;
static final int BOTHSPOONSDUKE = 2;
private int width = 0;
private int height = 0;
private double spacing;
private static final double MARGIN = 10.0f;
private Philosopher[] philosophers = new Philosopher[NUMPHILS];
public void init() {
imgs[HUNGRYDUKE] = new ImageIcon(getURL("images/hungryduke.gif"));
imgs[RIGHTSPOONDUKE] = new ImageIcon(
getURL("images/rightspoonduke.gif"));
imgs[BOTHSPOONSDUKE] = new ImageIcon(
getURL("images/bothspoonsduke.gif"));
width = imgs[HUNGRYDUKE].getIconWidth() + (int) (MARGIN * 2.0);
height = imgs[HUNGRYDUKE].getIconHeight() + (int) (MARGIN * 2.0);
spacing = width + MARGIN;
GridBagLayout gridBag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
JPanel contentPane = new JPanel();
contentPane.setLayout(gridBag);
philosopherArea = new JPanel(null);
philosopherArea.setBackground(Color.white);
Dimension preferredSize = createPhilosophersAndChopsticks();
philosopherArea.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLoweredBevelBorder(), BorderFactory
.createEmptyBorder(5, 5, 5, 5)));
philosopherArea.setPreferredSize(preferredSize);
c.fill = GridBagConstraints.BOTH;
c.weighty = 1.0;
c.gridwidth = GridBagConstraints.REMAINDER; //end row
gridBag.setConstraints(philosopherArea, c);
contentPane.add(philosopherArea);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
gridBag.setConstraints(stopStartButton, c);
contentPane.add(stopStartButton);
c.gridwidth = GridBagConstraints.RELATIVE; //don't end row
c.weightx = 1.0;
c.weighty = 0.0;
gridBag.setConstraints(grabDelaySlider, c);
contentPane.add(grabDelaySlider);
c.weightx = 0.0;
c.gridwidth = GridBagConstraints.REMAINDER; //end row
gridBag.setConstraints(label, c);
contentPane.add(label);
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
stopStartButton.addActionListener(this);
grabDelaySlider.addChangeListener(this);
}
public void actionPerformed(ActionEvent e) {
if (stopStartButton.getText().equals("stop/reset")) {
stopPhilosophers();
stopStartButton.setText("start");
} else if (stopStartButton.getText().equals("start")) {
startPhilosophers();
stopStartButton.setText("stop/reset");
}
}
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
grabDelay = source.getValue() * 100;
label.setText(String.valueOf(grabDelay + " milliseconds"));
}
public void startPhilosophers() {
for (int i = 0; i < NUMPHILS; i++)
philosophers[i].philThread.start();
}
public void stopPhilosophers() {
for (int i = 0; i < NUMPHILS; i++)
philosophers[i].philThread.interrupt();
}
public Dimension createPhilosophersAndChopsticks() {
double x, y;
double radius = 80.0;
double centerAdj = 85.0;
double radians;
Dimension preferredSize = new Dimension(0, 0);
/*
* for a straight line y = MARGIN;
*/
for (int i = 0; i < NUMPHILS; i++)
chopsticks[i] = new Chopstick();
for (int i = 0; i < NUMPHILS; i++) {
/*
* for a straight line x = i * spacing;
*/
radians = i * (2.0 * Math.PI / (double) NUMPHILS);
x = Math.sin(radians) * radius + centerAdj;
y = Math.cos(radians) * radius + centerAdj;
philosophers[i] = new Philosopher(this, i, imgs[HUNGRYDUKE]);
philosophers[i].setBounds((int) x, (int) y, width, height);
philosopherArea.add(philosophers[i]);
if ((int) x > preferredSize.width)
preferredSize.width = (int) x;
if ((int) y > preferredSize.height)
preferredSize.height = (int) y;
}
preferredSize.width += width;
preferredSize.height += height;
return preferredSize;
}
protected URL getURL(String filename) {
URL codeBase = getCodeBase();
URL url = null;
try {
url = new URL(codeBase, filename);
} catch (java.net.MalformedURLException e) {
System.out.println("Couldn't create image: "
+ "badly specified URL");
return null;
}
return url;
}
}
/*
* This class requires no changes from the 1.0 version. It's kept here so the
* rest of the example can compile.
*/
class Philosopher extends JLabel implements Runnable {
private Chopstick leftStick, rightStick;
private boolean sated;
private DiningPhilosophers parent;
private int position;
Thread philThread = null;
public Philosopher(DiningPhilosophers parent, int position, ImageIcon img) {
super(parent.names[position], img, JLabel.CENTER);
this.parent = parent;
this.position = position;
setVerticalTextPosition(JLabel.BOTTOM);
setHorizontalTextPosition(JLabel.CENTER);
// identify the chopsticks to my right and left
this.rightStick = parent.chopsticks[position];
if (position == 0) {
this.leftStick = parent.chopsticks[parent.NUMPHILS - 1];
} else {
this.leftStick = parent.chopsticks[position - 1];
}
// I'm hungry
this.sated = false;
philThread = new Thread(this);
}
public void run() {
try {
while (true) {
Thread.sleep((int) (Math.random() * parent.grabDelay));
setText(" ");
rightStick.grab();
setIcon(parent.imgs[parent.RIGHTSPOONDUKE]);
Thread.sleep((int) (Math.random() * parent.grabDelay));
leftStick.grab();
setIcon(parent.imgs[parent.BOTHSPOONSDUKE]);
Thread.sleep((int) (Math.random() * parent.grabDelay));
rightStick.release();
leftStick.release();
setIcon(parent.imgs[parent.HUNGRYDUKE]);
setText("Mmmm!");
sated = true;
Thread.sleep((int) (Math.random() * parent.grabDelay * 4));
sated = false;
}
} catch (java.lang.InterruptedException e) {
}
leftStick.releaseIfMine();
rightStick.releaseIfMine();
setIcon(parent.imgs[parent.HUNGRYDUKE]);
setText(parent.names[position]);
sated = false;
philThread = new Thread(this);
}
}
class Chopstick {
Thread holder = null;
public synchronized void grab() throws InterruptedException {
while (holder != null)
wait();
holder = Thread.currentThread();
}
public synchronized void release() {
holder = null;
notify();
}
public synchronized void releaseIfMine() {
if (holder == Thread.currentThread())
holder = null;
notify();
}
}