DiningPhilosophers.java Source code

Java tutorial

Introduction

Here is the source code for DiningPhilosophers.java

Source

/* 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();
    }
}