Thread Priority and Scheduling


Computing Pi

We will create and run two threads in the next program. One of them will operate a Pi generator with a really cool algorithm that can generate Pi to an unlimited number of digits one at a time. The other thread will be the thread that runs inside a ClockPanel1. PiPanel1 (example 16.8) creates a window with a ClockPanel1 at the top, a JTextArea in the center that displays Pi continuously appending the latest-generated digits, and a JButton at the bottom that can pause or play the Pi-generation. There is some significant code in PiPanel dealing with displaying Pi and scrolling the JTextArea as necessary so the latest digits are always in view. This code has nothing to do with threads and, for this chapter’s purposes, you may ignore it. On the other hand it might give you some insight into the handling of JTextAreas, JScrollPanes and JScrollBars, so it’s your choice. The PiSpigot class that generates Pi (example 16.9) is also not relevant to threads but it’s based on such an incredible algorithm that we will discuss it at the end of this chapter for readers that are interested.

Example 16.8: chap16.pi.PiPanel1.java

image from book
 1    package chap16.pi; 2 3    import java.awt.BorderLayout; 4    import java.awt.Font; 5    import java.awt.event.ActionEvent; 6    import java.awt.event.ActionListener; 7 8    import javax.swing.JButton; 9    import javax.swing.JFrame; 10   import javax.swing.JPanel; 11   import javax.swing.JScrollBar; 12   import javax.swing.JScrollPane; 13   import javax.swing.JTextArea; 14   import javax.swing.SwingConstants; 15   import javax.swing.SwingUtilities; 16 17   public class PiPanel1 extends JPanel implements ActionListener { 18     private JTextArea textArea; 19     private JButton spigotButton; 20     private PiSpigot spigot; 21     private int numDigits = 0; 22     private JScrollBar vScrollBar; 23     private JScrollPane scrollPane; 24     25     private boolean paused = true; 26     27     /* producerThread is protected so that a subclass can reference it. */ 28     protected Thread producerThread; 29 30     /* buttonPanel is protected so that a subclass can reference it. */ 31     protected final JPanel buttonPanel; 32 33     public PiPanel1() { 34       setLayout(new BorderLayout()); 35 36       textArea = new JTextArea(20, 123); 37       textArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); 38       textArea.setEditable(false); 39       scrollPane = new JScrollPane(textArea); 40       scrollPane.setHorizontalScrollBarPolicy( 41         JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 42       scrollPane.setVerticalScrollBarPolicy( 43         JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 44       add(scrollPane, BorderLayout.CENTER); 45     46       vScrollBar = scrollPane.getVerticalScrollBar(); 47 48       spigotButton = new JButton("Play"); 49       spigotButton.addActionListener(this); 50       buttonPanel = new JPanel(new BorderLayout()); 51       buttonPanel.add(spigotButton, BorderLayout.CENTER); 52       add(buttonPanel, BorderLayout.SOUTH); 53     54       spigot = new PiSpigot(); 55       startProducer(); 56     } 57 58     /* Thread-related methods */ 59     private void startProducer() { 60       producerThread = new Thread() { 61         public void run() { 62           while (true) { 63             Thread.yield(); 64             while (paused) { 65               pauseImpl(); 66             } 67             int digit = spigot.nextDigit(); 68             handleDigit(digit); 69           } 70         } 71       }; 72       producerThread.start(); 73      } 74 75      /* pauseImpl will be implemented differently in a future subclass */ 76      protected void pauseImpl() { 77        try { 78          Thread.sleep(Long.MAX_VALUE); 79        } catch (InterruptedException e) {} 80      } 81      private void play() { 82        paused = false; 83        playImpl(); 84      } 85      /* playImpl will be implemented differently in a future subclass */ 86      protected void playImpl() { 87        producerThread.interrupt(); 88      } 89      private void pause() { 90        paused = true; 91      } 92     93      /* Play/Pause Button */ 94      public void actionPerformed(ActionEvent e) { 95        String action = spigotButton.getText(); 96        if ("Play".equals(action)) { 97          play(); 98          spigotButton.setText("Pause"); 99        } else { 100          pause(); 101          spigotButton.setText("Play"); 102        } 103      } 104     105      /* GUI-related methods */ 106      protected void showLastLine() { 107        /* 108         * These swing conponent methods are not thread-safe 109         * so we use SwingUtilities.invokeLater 110         */ 111        SwingUtilities.invokeLater(new Runnable() { 112          public void run() { 113            JScrollBar vScrollBar = scrollPane.getVerticalScrollBar(); 114            int numLines = textArea.getLineCount(); 115            int lineHeight = 116              textArea.getScrollableUnitIncrement( 117                scrollPane.getViewport().getViewRect(), 118                SwingConstants.VERTICAL, 119                -1); 120            int visibleHeight = vScrollBar.getVisibleAmount(); 121            int numVisibleLines = visibleHeight / lineHeight; 122            int scroll = (numLines - numVisibleLines) * lineHeight; 123            vScrollBar.setValue(scroll); 124          } 125        }); 126      } 127      protected void displayDigit(int digit) { 128        if (numDigits == 1) { 129          textArea.append("."); 130        } 131        textArea.append(String.valueOf(digit)); 132        numDigits++; 133        if (numDigits > 1) { 134          if ((numDigits - 1) % 100 == 0) { 135            textArea.append("\n  "); //JTextArea.append is thread-safe 136            showLastLine(); 137          } else if ((numDigits - 1) % 5 == 0) { 138            textArea.append(" "); //JTextArea.append is thread-safe 139          } 140        } 141      } 142      /* handleDigit will be implemented differently in a future subclass */ 143      protected void handleDigit(int digit) { 144        displayDigit(digit); 145      } 146      public static void main(String[] arg) { 147        JFrame f = new JFrame(); 148        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 149        f.getContentPane().add(new PiPanel1(), BorderLayout.CENTER); 150        f.getContentPane().add(new chap16.clock.ClockPanel1(), BorderLayout.NORTH); 151        f.pack(); 152        f.show(); 153      } 154     }
image from book

Example 16.9: chap16.pi.PiSpigot.java

image from book
 1    package chap16.pi; 2 3    import java.math.BigInteger; 4 5    public class PiSpigot { 6      private static final BigInteger zero = BigInteger.ZERO; 7      private static final BigInteger one = BigInteger.ONE; 8      private static final BigInteger two = BigInteger.valueOf(2); 9      private static final BigInteger three = BigInteger.valueOf(3); 10     private static final BigInteger four = BigInteger.valueOf(4); 11     private static final BigInteger ten = BigInteger.valueOf(10); 12     13     private BigInteger q = one; 14     private BigInteger r = zero; 15     private BigInteger t = one; 16     private BigInteger k = one; 17     private BigInteger n = zero; 18     19     public int nextDigit() { 20       while (true) { 21         n = three.multiply(q).add(r).divide(t); 22         if (four.multiply(q).add(r).divide(t).equals(n)) { 23           q = ten.multiply(q); 24           r = ten.multiply(r.subtract(n.multiply(t))); 25           return n.intValue(); 26         } else { 27           BigInteger temp_q = q.multiply(k); 28           BigInteger temp_2k_plus_1 = two.multiply(k).add(one); 30           BigInteger temp_t = t.multiply(temp_2k_plus_1); 29           BigInteger temp_r = two.multiply(q).add(r).multiply(temp_2k_plus_1); 31           BigInteger temp_k = k.add(one); 32           q = temp_q; 33           r = temp_r; 34           t = temp_t; 35           k = temp_k; 36         } 37       } 38     } 39    }
image from book

Use the following commands to compile and execute the example. From the directory containing the src folder:

      javac –d classes -sourcepath src src/chap16/pi/PiPanel1.java      java –cp classes chap16.pi.PiPanel1

After PiPanel1’s constructor assembles the GUI, it calls startProducer() (line 55) which creates a Thread whose run() method is an infinite digit-producing loop. Every time it goes through the body of the loop, it politely calls Thread.yield() (line 63). Calling Thread.yield() allows other threads that may have been waiting a chance to execute, possibly causing the current thread to pause its own execution. If no threads were waiting, the current thread just continues. Since digit producing is CPU intensive and because this loop never ends, calling Thread.yield() is more than just polite. It’s the right thing to do. Table 16-6 lists Thread’s yield() method.

Table 16-6: Calling the Thread.yield() Method

Method Name and Purpose

public static void yield()

Allows other threads that may have been waiting a chance to execute, possibly causing the current thread to pause its own execution.

Let’s discuss the logic of the producer thread’s run() method. (See lines 61 - 70 of example 16-8). After calling thread.yield(), the loop’s next action depends on the value of the boolean variable, paused. If paused is false, the loop produces another digit, calls handleDigit() and repeats. If paused is true, the thread enters the while(paused) loop which calls pauseImpl() causing the thread to sleep. Unless it is interrupted, the producer thread will exit sleep(Long.MAX_VALUE) only after approximately 300 million years. If it does sleep this long, the while(paused) loop will notice that paused is still true and will send the thread back to sleep again. I think it’s more likely that the producer thread will exit sleep by being interrupted. How about you?

If the “Play” button is pressed while the producer is sleeping, the play() method will set paused to false and call playImpl() which wakes the producerThread up by calling producerThread.interrupt(). This will cause the while(paused) loop to exit since paused is no longer true, and digit-producing to resume. If, on the other hand, the “Pause” button is pressed while the producer is running, the producer thread will enter the while(paused) loop automatically on the very next digit-producing iteration and begin sleeping. This use of sleep() and interrupt() is somewhat unconventional. Later in the chapter, we will discuss a more appropriate mechanism for achieving the same results.

Quick Review

The sleep() and interrupt() methods can be used as a mechanism for regulating a thread’s use of the CPU. If a thread’s run() method is time consuming, it should call yield() periodically to allow other threads a chance to run.




Java For Artists(c) The Art, Philosophy, and Science of Object-Oriented Programming
Java For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504052
EAN: 2147483647
Year: 2007
Pages: 452

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net