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