201771010101 白瑪次仁 《2018面向物件程式設計(Java)》第十六週學習總結
實驗十六 執行緒技術
實驗時間 2017-12-8
1.學習總結:
1.程式 是一段靜態的程式碼,它應用程式執行藍 是一段靜態的程式碼,它應用程式執行藍 本。
2.程序 是程式的一次動態執行,它對應了從程式碼加 是程式的一次動態執行,,它對應了從程式碼加 載、執行至完畢的一個整過程。
3.作業系統為每個程序分配一段獨立的記憶體空間和 系統資源,包括:程式碼資料以及堆疊等。每 系統資源,包括:程式碼資料以及堆疊等。每 一個程序的內部資料和狀態都是完全獨立。
4.多工作業系統 中,程序切換對 CPU 資源消耗較 大。多執行緒 是程序執行過中產生的多條線索。 執行緒是比進執行更小的單位。執行緒不能獨立存在,必須於進 中同一程的各線間共享進空資料。 程的各線共享進空資料。每個執行緒有它自身的產生、存在和消亡過, 是一個動態的概念。
5.Java 實現多執行緒有兩種途徑:
1.建立 Thread 類的子
2.在程式中定義實現 Runnable 介面的類
6.首先需從 Thread 類派生出一個子, 在該子類中 重寫 run()方法。
首先設計一個實現 Runnable 介面的類; 介面的類; 介面的類; 介面的類; 介面的類;
7. 用Runnable() 介面實現執行緒
1.首先設計一個實現 Runnable 介面的類
2.然後在類中根據需要重寫 run 方法;
3再建立該類物件,以此為引數立 再建立該類物件,以此為引數立 Thread類的物件;
4.呼叫 Thread 類物件的 start 方法啟動執行緒,將 CPU 執行權轉交到 run 方法。
8.當執行緒的 run 方法執行體中最後 一條語句方法執行體中最後 一條語句, 或者出現了在 run 方法中沒有捕獲的異常時 ,線 程將終止 ,讓出 CPU 使用權 。
9.利用各執行緒的狀態變換,可以控制個輪流 利用各執行緒的狀態變換, 使用 CPU ,體現多執行緒的 並行性特徵。
10.執行緒的終止:當執行緒的run方法執行方法體中最後一條語句後, 或者出現了在run方法中沒有捕獲的異常時,線 程將終止,讓出CPU使用權。呼叫interrupt()方法也可終止執行緒。
11.執行緒的狀態:利用各執行緒的狀態變換,可以控制各個執行緒輪流 使用CPU,體現多執行緒的並行性特徵。執行緒有如下7種狀態: New (新建) 、Runnable (可執行) 、Running(執行) 、Blocked (被阻塞) 、Waiting (等待) 、Timed waiting (計時等待) 、Terminated (被終止)
12.呼叫setPriority(int a)重置當前執行緒的優先順序, a 取值可以是前述的三個靜態量。
2、實驗目的與要求
(1) 掌握執行緒概念;
(2) 掌握執行緒建立的兩種技術;
(3) 理解和掌握執行緒的優先順序屬性及排程方法;
(4) 掌握執行緒同步的概念及實現技術;
3、實驗內容和步驟
實驗1:測試程式並進行程式碼註釋。
測試程式1:
l 在elipse IDE中除錯執行ThreadTest,結合程式執行結果理解程式;
l 掌握執行緒概念;
l 掌握用Thread的擴充套件類實現執行緒的方法;
l 利用Runnable介面改造程式,掌握用Runnable介面建立執行緒的方法。
class Lefthand extends Thread { 2 public void run() 3 { 4 for(int i=0;i<=5;i++) 5 { System.out.println("You are Students!"); 6 try{ sleep(500); } 7 catch(InterruptedException e) 8 { System.out.println("Lefthand error.");} 9 } 10 } 11 } 12 class Righthand extends Thread { 13 public void run() 14 { 15 for(int i=0;i<=5;i++) 16 { System.out.println("I am a Teacher!"); 17 try{ sleep(300); } 18 catch(InterruptedException e) 19 { System.out.println("Righthand error.");} 20 } 21 } 22 } 23 public class ThreadTest 24 { 25 static Lefthand left; 26 static Righthand right; 27 public static void main(String[] args) 28 { left=new Lefthand(); 29 right=new Righthand(); 30 left.start(); 31 right.start(); 32 } 33 }
package gfhc; 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.");} } Lefthand left=new Lefthand (); Righthand right=new Righthand (); } } public class fgyukg { 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,結合程式執行結果理解程式;
package bounce; 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 bounce; 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 JPanel { 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 component. * @param b the ball to add */ public void add(Ball b) { balls.add(b); } public void paintComponent(Graphics g) { super.paintComponent(g); // erase background 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() //BounceFrame類的addBall方法中有呼叫comp.paint(comp.getGraphics()) { 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()//Start按鈕的處理程式將呼叫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是 Thread累靜態方法,用於暫停當前執行緒的活動。 } } catch (InterruptedException e) //InterruptedException 只是在發生異常時簡單地終止彈跳。 { } } }
l 在Elipse環境下除錯教材631頁程式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();//啟動執行緒
} }
l 對比兩個程式,理解執行緒的概念和用途;
l 掌握執行緒建立的兩種技術。
測試程式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()+"已計算完畢!"); } } |
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);//將指定的 double 值分配給指定 double 型陣列的每個元素 } /** * 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); t.start(); } } }
綜合程式設計練習
程式設計練習1
- 設計一個使用者資訊採集程式,要求如下:
(1) 使用者資訊輸入介面如下圖所示:
(2) 使用者點選提交按鈕時,使用者輸入資訊顯示控制檯介面;
(3) 使用者點選重置按鈕後,清空使用者已輸入資訊;
(4) 點選視窗關閉,程式退出。
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); } }
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 male; private JRadioButton female; private JCheckBox read; private JCheckBox movie; private JCheckBox learn; 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();//構造一個新的 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));//建立具有指定行數和列數的網格佈局。給佈局中的所有元件分配相等的大小。 read = new JCheckBox("讀書"); movie = new JCheckBox("看電影"); learn = new JCheckBox("學習"); selectBox.add(read); selectBox.add(movie); selectBox.add(learn); 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(); male = new JRadioButton("男"); female = new JRadioButton("女"); bg.add(male); bg.add(female); selectBox.add(male); selectBox.add(female); 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 (read.isSelected()) { hobbystring+="讀書 "; } if (movie.isSelected()) { hobbystring+="看電影 "; } if (learn.isSelected()) { hobbystring+="學習 "; } System.out.println(address); if (male.isSelected()) { System.out.println("男"); } if (female.isSelected()) { System.out.println("女"); } System.out.println(hobbystring); } /* * 重置 */ private void Reset() { // TODO 自動生成的方法存根 fieldadress.setText(null); fieldname.setText(null); comboBox.setSelectedIndex(0); read.setSelected(false); movie.setSelected(false); learn.setSelected(false); bg.clearSelection(); } }
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Main { public static void main(String[] args) { EventQueue.invokeLater(() -> { DemoJFrame page = new DemoJFrame(); }); } }
2.建立兩個執行緒,每個執行緒按順序輸出5次“你好”,每個“你好”要標明來自哪個執行緒及其順序號。
package project2; class Lefthand extends Thread { public void run() { for(int i=0;i<=4;i++) { System.out.println("1.你好"); try{ sleep(500); } catch(InterruptedException e) { System.out.println("Lefthand error.");} } } } class Righthand extends Thread { public void run() { for(int i=0;i<=4;i++) { System.out.println("2.你好"); try{ sleep(300); } catch(InterruptedException e) { System.out.println("Righthand error.");} } } } public class ThreadText { static Lefthand left; static Righthand right; public static void main(String[] args) { left=new Lefthand(); right=new Righthand(); left.start(); right.start(); } }
實驗總結:這次實驗執行多個程式的能力。例:作業系統將CPU的時間片分配給每一個程序,給人並行處理的感覺。
重要比較了多執行緒和多程序有哪些區別等,好多知識的收穫。