1. 程式人生 > >16窮吉201771010119

16窮吉201771010119

實驗十六  執行緒技術

 

理論知識:

程式是一段靜態的程式碼,它是應用程式執行的藍
本。
‐程序是程式的一次動態執行,它對應了從程式碼加
載、執行至執行完畢的一個完整過程。

多執行緒是程序執行過程中產生的多條執行線索。
‐執行緒是比程序執行更小的單位。
‐執行緒不能獨立存在,必須存在於程序中,同一進
程的各執行緒間共享程序空間的資料。
‐每個執行緒有它自身的產生、存在和消亡的過程,
是一個動態的概念。
‐多執行緒意味著一個程式的多行語句可以看上去幾
乎在同一時間內同時執行。

(2)Java中實現多執行緒的途徑有兩種:

‐建立Thread類的子類

<1>用Thread類的子類建立執行緒

首先需從Thread類派生出一個子類,在該子類中
重寫run()方法。
例:
class hand extends Thread

public void run()
{……} 
}

<2>然後用建立該子類的物件
Lefthand left=new Lefthand();
Righthand right=new Righthand();
<3>最後用start()方法啟動執行緒
left.start();
right.start();

用Thread類的子類建立多執行緒的關鍵性操作

–定義Thread類的子類並實現使用者執行緒操作,即

run()方法的實現。

實驗目的與要求

(1) 掌握執行緒概念;

(2) 掌握執行緒建立的兩種技術;

(3) 理解和掌握執行緒的優先順序屬性及排程方法;

(4) 掌握執行緒同步的概念及實現技術;

2、實驗內容和步驟

實驗1:測試程式並進行程式碼註釋。

測試程式1:

l  在elipse IDE中除錯執行ThreadTest,結合程式執行結果理解程式;

l  掌握執行緒概念;

l  掌握用Thread的擴充套件類實現執行緒的方法;

l  利用Runnable介面改造程式,掌握用Runnable介面建立執行緒的方法。

class Lefthand extends Thread {

   public void run()

   {

       for(int i=0;i<=5;i++)

       {  System.out.println("You are Students!");

           try{   sleep(500);   }

           catch(InterruptedException e)

           { System.out.println("Lefthand error.");}   

       }

  }

}

class Righthand extends Thread {

    public void run()

    {

         for(int i=0;i<=5;i++)

         {   System.out.println("I am a Teacher!");

             try{  sleep(300);  }

             catch(InterruptedException e)

             { System.out.println("Righthand error.");}

         }

    }

}

public class ThreadTest

{

     static Lefthand left;

     static Righthand right;

     public static void main(String[] args)

     {     left=new Lefthand();

           right=new Righthand();

           left.start();

           right.start();

     }

}

用 Runnable介面改造後的程式

package ceshi;
class Lefthand implements Runnable {
public void run()
{
for(int i=0;i<=5;i++)
{ System.out.println("You are Students!");
try{ Thread. sleep(500); }
catch(InterruptedException e)
{ System.out.println("Lefthand error.");}
}
}

}




class Righthand implements Runnable {
public void run()
{
for(int i=0;i<=5;i++)
{ System.out.println("I am a Teacher!");
try{ Thread. sleep(300); }
catch(InterruptedException e)
{ System.out.println("Righthand error.");}
}
}



}


public class ThreadTest
{
static Lefthand left;
static Righthand right;
public static void main(String[] args)
{ //left=new Lefthand();
//right=new Righthand();
// left.start();
//right.start();
Runnable Lefthand=new Lefthand();
Thread t=new Thread(Lefthand);
t.start();
Runnable Righthand=new Righthand();
Thread t1=new Thread(Righthand);
t1.start();


}

}

測試程式2:

l  在Elipse環境下除錯教材625頁程式14-1、14-2 、14-3,結合程式執行結果理解程式;

  在Elipse環境下除錯教材631頁程式14-4,結合程式執行結果理解程式;

l  對比兩個程式,理解執行緒的概念和用途;

l  掌握執行緒建立的兩種技術

package bounceThread;

import java.awt.geom.*;

/**
   A ball that moves and bounces off the edges of a 
   rectangle
 * @version 1.33 2007-05-17
 * @author Cay Horstmann
*/
public class Ball
{
   private static final int XSIZE = 15;
   private static final int YSIZE = 15;
   private double x = 0;
   private double y = 0;
   private double dx = 1;
   private double dy = 1;

   /**
      Moves the ball to the next position, reversing direction
      if it hits one of the edges
   */
   //判斷球的邊界所處狀態的四個條件
   public void move(Rectangle2D bounds)
   {
      x += dx;
      y += dy;
      if (x < bounds.getMinX())
      { 
         x = bounds.getMinX();
         dx = -dx;
      }
      if (x + XSIZE >= bounds.getMaxX())
      {
         x = bounds.getMaxX() - XSIZE; 
         dx = -dx; 
      }
      if (y < bounds.getMinY())
      {
         y = bounds.getMinY(); 
         dy = -dy;
      }
      if (y + YSIZE >= bounds.getMaxY())
      {
         y = bounds.getMaxY() - YSIZE;
         dy = -dy; 
      }
   }

   /**
      Gets the shape of the ball at its current position.
   */
   public Ellipse2D getShape()
   {
      return new Ellipse2D.Double(x, y, XSIZE, YSIZE);
   }
}
package bounceThread;

import java.awt.*;
import java.util.*;
import javax.swing.*;

/**
 * The component that draws the balls.
 * @version 1.34 2012-01-26
 * @author Cay Horstmann
 */
public class BallComponent extends JComponent
{
   private static final int DEFAULT_WIDTH = 450;
   private static final int DEFAULT_HEIGHT = 350;

   private java.util.List<Ball> balls = new ArrayList<>();

   /**
    * Add a ball to the panel.
    * @param b the ball to add
    */
   public void add(Ball b)
   {
      balls.add(b);
   }

   public void paintComponent(Graphics g)
   {
      Graphics2D g2 = (Graphics2D) g;
      for (Ball b : balls)
      {
         g2.fill(b.getShape());
      }
   }
   
   public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
}

package bounce;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * Shows an animated bouncing ball.
 * @version 1.34 2015-06-21
 * @author Cay Horstmann
 */
public class Bounce
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(() -> {
         JFrame frame = new BounceFrame();
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);
      });
   }
}

/**
 * The frame with ball component and buttons.
 */
class BounceFrame extends JFrame
{
   private BallComponent comp;
   public static final int STEPS = 1000;
   public static final int DELAY = 3;

   /**
    * Constructs the frame with the component for showing the bouncing ball and
    * Start and Close buttons
    */
   public BounceFrame()
   {
      setTitle("Bounce");
      comp = new BallComponent();
      add(comp, BorderLayout.CENTER);
      JPanel buttonPanel = new JPanel();
      addButton(buttonPanel, "Start", event -> addBall());
      addButton(buttonPanel, "Close", event -> System.exit(0));
      add(buttonPanel, BorderLayout.SOUTH);//將buttonPanel元件整體放在南端
      pack();
   }

   /**
    * Adds a button to a container.
    * @param c the container
    * @param title the button title
    * @param listener the action listener for the button
    */
   public void addButton(Container c, String title, ActionListener listener)
   {
      JButton button = new JButton(title);
      c.add(button);
      button.addActionListener(listener);
   }

   /**
    * Adds a bouncing ball to the panel and makes it bounce 1,000 times.
    */
   public void addBall()
   {
      try
      {
         Ball ball = new Ball();
         comp.add(ball);

         for (int i = 1; i <= STEPS; i++)
         {
            ball.move(comp.getBounds());//呼叫move方法
            comp.paint(comp.getGraphics());
            Thread.sleep(DELAY);//呼叫執行緒的sleep方法
         }
      }
      catch (InterruptedException e)
      {
      }
   }
}
14-4

 

package bounceThread;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

/**
 * Shows animated bouncing balls.
 * @version 1.34 2015-06-21
 * @author Cay Horstmann
 */
public class BounceThread
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(() -> {
         JFrame frame = new BounceFrame();
         frame.setTitle("BounceThread");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);
      });
   }
}

/**
 * The frame with panel and buttons.
 */
class BounceFrame extends JFrame
{
   private BallComponent comp;
   public static final int STEPS = 1000;
   public static final int DELAY = 5;


   /**
    * Constructs the frame with the component for showing the bouncing ball and
    * Start and Close buttons
    */
   public BounceFrame()
   {
      comp = new BallComponent();
      add(comp, BorderLayout.CENTER);
      JPanel buttonPanel = new JPanel();
      addButton(buttonPanel, "Start", event -> addBall());
      addButton(buttonPanel, "Close", event -> System.exit(0));
      add(buttonPanel, BorderLayout.SOUTH);
      pack();
   }

   /**
    * Adds a button to a container.
    * @param c the container
    * @param title the button title
    * @param listener the action listener for the button
    */
   public void addButton(Container c, String title, ActionListener listener)
   {
      JButton button = new JButton(title);
      c.add(button);
      button.addActionListener(listener);
   }

   /**
    * Adds a bouncing ball to the canvas and starts a thread to make it bounce
    */
   public void addBall()
   {
      Ball ball = new Ball();
      comp.add(ball);
      //引用實現了Runnable的方法
      Runnable r = () -> { 
         try
         {  
            for (int i = 1; i <= STEPS; i++)
            {
               ball.move(comp.getBounds());
               comp.repaint();
               Thread.sleep(DELAY);
            }
         }
         catch (InterruptedException e)
         {
         }
      };
      Thread t = new Thread(r);//用Runnable建立一個Thread物件
      t.start();//啟動執行緒
   }
}

 

測試程式3:分析以下程式執行結果並理解程式。

class Race extends Thread {

  public static void main(String args[]) {

    Race[] runner=new Race[4];

    for(int i=0;i<4;i++) runner[i]=new Race( );

   for(int i=0;i<4;i++) runner[i].start( );

   runner[1].setPriority(MIN_PRIORITY);// 更改執行緒優先順序,執行緒可以具有的最低優先順序

 runner[3].setPriority(MAX_PRIORITY);} // 更改執行緒的優先順序,執行緒可以具有的最高優先順序

  public void run( ) {

      for(int i=0; i<1000000; i++);

      System.out.println(getName()+"執行緒的優先順序是"+getPriority()+"已計算完畢!");

    }

}

 

 

測試程式4

l  教材642頁程式模擬一個有若干賬戶的銀行,隨機地生成在這些賬戶之間轉移錢款的交易。每一個賬戶有一個執行緒。在每一筆交易中,會從執行緒所服務的賬戶中隨機轉移一定數目的錢款到另一個隨機賬戶。

l  在Elipse環境下除錯教材642頁程式14-5、14-6,結合程式執行結果理解程式;

程式碼:

package unsynch;

import java.util.*;

/**
 * A bank with a number of bank accounts.
 * 
 * @version 1.30 2004-08-01
 * @author Cay Horstmann
 */
public class Bank {
    private final double[] accounts;

    /**
     * Constructs the bank.
     * 
     * @param n              the number of accounts
     * @param initialBalance the initial balance for each account
     */
    public Bank(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * Transfers money from one account to another.
     * 
     * @param from   the account to transfer from
     * @param to     the account to transfer to
     * @param amount the amount to transfer
     */
    public void transfer(int from, int to, double amount) {
        if (accounts[from] < amount)
            return;
        System.out.print(Thread.currentThread());//返回對當前正在執行的執行緒物件的引用
        accounts[from] -= amount;
        System.out.printf(" %10.2f from %d to %d", amount, from, to);
        accounts[to] += amount;
        System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
    }

    /**
     * Gets the sum of all account balances.
     * 
     * @return the total balance
     */
    public double getTotalBalance() {
        double sum = 0;

        for (double a : accounts)
            sum += a;

        return sum;
    }

    /**
     * Gets the number of accounts in the bank.
     * 
     * @return the number of accounts
     */
    public int size() {
        return accounts.length;
    }
}

package unsynch;

/**
 * This program shows data corruption when multiple threads access a data
 * structure.
 * 
 * @version 1.31 2015-06-21
 * @author Cay Horstmann
 */
public class UnsynchBankTest {
    public static final int NACCOUNTS = 100;
    public static final double INITIAL_BALANCE = 1000;
    public static final double MAX_AMOUNT = 1000;
    public static final int DELAY = 10;

    public static void main(String[] args) {
        Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
        for (int i = 0; i < NACCOUNTS; i++) {
            int fromAccount = i;
            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));//在指定的毫秒數內讓當前正在執行的執行緒休眠
                    }
                } catch (InterruptedException e) {
//當執行緒在活動之前或活動期間處於正在等待、休眠或佔用狀態且該執行緒被中斷時,丟擲該異常
} }; Thread t = new Thread(r);//分配新的 Thread 物件 t.start();//使該執行緒開始執行 } } }
 



綜合程式設計練習

程式設計練習1

  1. 1.         設計一個使用者資訊採集程式,要求如下:

(1)   使用者資訊輸入介面如下圖所示:

 

 

(2)   使用者點選提交按鈕時,使用者輸入資訊顯示控制檯介面;

(3)   使用者點選重置按鈕後,清空使用者已輸入資訊;

(4)   點選視窗關閉,程式退出。

程式碼:

package 銀行;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

public class DemoJFrame extends JFrame {
private JPanel jPanel1;
private JPanel jPanel2;
private JPanel jPanel3;
private JPanel jPanel4;
private JTextField fieldname;
private JComboBox comboBox;
private JTextField fieldadress;
private ButtonGroup bg;
private JRadioButton nan;
private JRadioButton nv;
private JCheckBox sing;
private JCheckBox dance;
private JCheckBox draw;

public DemoJFrame() {
// 設定視窗大小
this.setSize(800, 400);
// 設定可見性
this.setVisible(true);
// 設定標題
this.setTitle("程式設計練習一");
// 設定關閉操作
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
// 設定視窗居中
WinCenter.center(this);
// 建立四個面板物件
jPanel1 = new JPanel();
setJPanel1(jPanel1);
jPanel2 = new JPanel();
setJPanel2(jPanel2);
jPanel3 = new JPanel();
setJPanel3(jPanel3);
jPanel4 = new JPanel();
setJPanel4(jPanel4);
// 設定容器的為流佈局
FlowLayout flowLayout = new FlowLayout();
this.setLayout(flowLayout);
// 將四個面板新增到容器中
this.add(jPanel1);
this.add(jPanel2);
this.add(jPanel3);
this.add(jPanel4);

}

/*
* 設定面一
*/
private void setJPanel1(JPanel jPanel) {
// TODO 自動生成的方法存根
jPanel.setPreferredSize(new Dimension(700, 45));
// 給面板的佈局設定為網格佈局 一行4列
jPanel.setLayout(new GridLayout(1, 4));
JLabel name = new JLabel("姓名:");
name.setSize(100, 50);
fieldname = new JTextField("");
fieldname.setSize(80, 20);
JLabel study = new JLabel("學歷:");
comboBox = new JComboBox();
comboBox.addItem("初中");
comboBox.addItem("高中");
comboBox.addItem("本科");
jPanel.add(name);
jPanel.add(fieldname);
jPanel.add(study);
jPanel.add(comboBox);

}

/*
* 設定面板二
*/
private void setJPanel2(JPanel jPanel) {
// TODO 自動生成的方法存根
jPanel.setPreferredSize(new Dimension(700, 50));
// 給面板的佈局設定為網格佈局 一行4列
jPanel.setLayout(new GridLayout(1, 4));
JLabel name = new JLabel("地址:");
fieldadress = new JTextField();
fieldadress.setPreferredSize(new Dimension(150, 50));
JLabel study = new JLabel("民族:");
JPanel selectBox = new JPanel();
selectBox.setBorder(BorderFactory.createTitledBorder(""));
selectBox.setLayout(new GridLayout(3, 1));

//建立具有指定行數和列數的網格佈局。給佈局中的所有元件分配相等的大小


sing = new JCheckBox("藏族");
dance = new JCheckBox("漢族");
draw = new JCheckBox("蒙古族");
selectBox.add(sing);
selectBox.add(dance);
selectBox.add(draw);
jPanel.add(name);
jPanel.add(fieldadress);
jPanel.add(study);
jPanel.add(selectBox);
}

/*
* 設定面板三
*/
private void setJPanel3(JPanel jPanel) {
// TODO 自動生成的方法存根
jPanel.setPreferredSize(new Dimension(700, 150));
FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT);
jPanel.setLayout(flowLayout);
JLabel sex = new JLabel("性別:");
JPanel selectBox = new JPanel();
selectBox.setBorder(BorderFactory.createTitledBorder(""));
selectBox.setLayout(new GridLayout(2, 1));
bg = new ButtonGroup();
nan = new JRadioButton("男");
nv = new JRadioButton("女");
bg.add(nan);
bg.add(nv);
selectBox.add(nan);
selectBox.add(nv);
jPanel.add(sex);
jPanel.add(selectBox);

}

/*
* 設定面板四
*/
private void setJPanel4(JPanel jPanel) {
// TODO 自動生成的方法存根
jPanel.setPreferredSize(new Dimension(700, 150));
FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER, 50, 10);
jPanel.setLayout(flowLayout);
jPanel.setLayout(flowLayout);
JButton sublite = new JButton("提交");
JButton reset = new JButton("重置");
sublite.addActionListener((e) -> valiData());
reset.addActionListener((e) -> Reset());
jPanel.add(sublite);
jPanel.add(reset);
}

/*
* 提交資料
*/
private void valiData() {
// TODO 自動生成的方法存根
// 拿到資料
String name = fieldname.getText().toString().trim();
String xueli = comboBox.getSelectedItem().toString().trim();
String address = fieldadress.getText().toString().trim();
System.out.println(name);
System.out.println(xueli);
String hobbystring="";
if (sing.isSelected()) {
hobbystring+="藏族 ";
}
if (dance.isSelected()) {
hobbystring+="漢族 ";
}
if (draw.isSelected()) {
hobbystring+="蒙古族 ";
}
System.out.println(address);
if (nan.isSelected()) {
System.out.println("男");
}
if (nv.isSelected()) {
System.out.println("女");
}
System.out.println(hobbystring);
}

/*
* 重置
*/
private void Reset() {
// TODO 自動生成的方法存根
fieldadress.setText(null);
fieldname.setText(null);
comboBox.setSelectedIndex(0);
sing.setSelected(false);
dance.setSelected(false);
draw.setSelected(false);
bg.clearSelection();
}
}

 

package 銀行;

import java.awt.EventQueue;

import javax.swing.JFrame;

public class Mian {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
DemoJFrame page = new DemoJFrame();
});
}
}

package 銀行;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;

public class WinCenter {
public static void center(Window win){
Toolkit tkit = Toolkit.getDefaultToolkit();
Dimension sSize = tkit.getScreenSize();
Dimension wSize = win.getSize();
if(wSize.height > sSize.height){
wSize.height = sSize.height;
}
if(wSize.width > sSize.width){
wSize.width = sSize.width;
}
win.setLocation((sSize.width - wSize.width)/ 2, (sSize.height - wSize.height)/ 2);
}
}

 結果圖:

2.建立兩個執行緒,每個執行緒按順序輸出5次“你好”,每個“你好”要標明來自哪個執行緒及其順序號。

package 執行緒;

 

class xiancheng1 extends Thread {
public void run()
{
for(int i=1;i<=5;i++)
{ System.out.println( i+ "你好~"+"(執行緒1)");
try{ sleep(500); }
catch(InterruptedException e)//異常捕獲
{ System.out.println("Lefthand error.");}
}
}
}

class xiancheng2 extends Thread {
public void run()
{
for(int i=1;i<=5;i++)
{ System.out.println( i+ "你好~"+"(執行緒2)");
try{ sleep(500); }
catch(InterruptedException e)//異常捕獲
{ System.out.println("Lefthand error.");}
}
}

}
public class xiancheng
{
//屬性
static xiancheng1 xian1;
static xiancheng2 xian2;
public static void main(String[] args)
{ xian1=new xiancheng1();
xian2=new xiancheng2();
//用start()方法啟動執行緒
xian1.start();
xian2.start();
}

}

 

 

3. 完善實驗十五 GUI綜合程式設計練習程式。

 實驗總結:這一章節我們學習了關於執行緒的知識點,掌握執行緒的概念和定義並進行運用。