一:理論知識java
1.線程的概念:編程
程序是一段靜態的代碼,它是應用程序執行的藍
本。
‐進程是程序的一次動態執行,它對應了從代碼加
載、執行至執行完畢的一個完整過程。canvas
多線程是進程執行過程當中產生的多條執行線索。
‐線程是比進程執行更小的單位。
‐線程不能獨立存在,必須存在於進程中,同一進
程的各線程間共享進程空間的數據。
‐每一個線程有它自身的產生、存在和消亡的過程,
是一個動態的概念。
‐多線程意味着一個程序的多行語句能夠看上去幾
乎在同一時間內同時運行。多線程
(2)Java中實現多線程的途徑有兩種:併發
‐建立Thread類的子類框架
<1>用Thread類的子類建立線程dom
首先需從Thread類派生出一個子類,在該子類中
重寫run()方法。
例:
class hand extends Thread
{
public void run()
{……}
}ide
<2>而後用建立該子類的對象
Lefthand left=new Lefthand();
Righthand right=new Righthand();
<3>最後用start()方法啓動線程
left.start();
right.start();佈局
用Thread類的子類建立多線程的關鍵性操做學習
–定義Thread類的子類並實現用戶線程操做,即
run()方法的實現。
–在適當的時候啓動線程。
因爲Java只支持單重繼承,用這種方法定義的類不可再繼承其餘父類。
‐在程序中定義實現Runnable接口的類
(2)用Runnable()接口實現線程:
⚫ 首先設計一個實現Runnable接口的類;
⚫ 而後在類中根據須要重寫run方法;
⚫ 再建立該類對象,以此對象爲參數創建Thread
類的對象;
⚫ 調用Thread類對象的start方法啓動線程,將
CPU執行權轉交到run方法。
2.中斷線程:
⚫ 當線程的run方法執行方法體中最後一條語句後,
或者出現了在run方法中沒有捕獲的異常時,線
程將終止,讓出CPU使用權。
⚫ 調用interrupt()方法也可終止線程。
void interrupt()
– 向一個線程發送一箇中斷請求,同時把這個線
程的「interrupted」狀態置爲true。
– 若該線程處於 blocked 狀 態 , 會拋出
InterruptedException。
(2)測試線程是否被中斷的方法
Java提供了幾個用於測試線程是否被中斷的方法。
⚫ static boolean interrupted()
– 檢測當前線程是否已被中斷 , 並重置狀態
「interrupted」值爲false。
⚫ boolean isInterrupted()
– 檢測當前線程是否已被中斷 , 不改變狀態
「interrupted」值 。
3.線程狀態:
利用各線程的狀態變換,能夠控制各個線程輪流
使用CPU,體現多線程的並行性特徵。
⚫ 線程有以下7種狀態:
➢ New (新建)
⚫ new(新建)
線程對象剛剛建立,尚未啓動,此時線程
還處於不可運行狀態。例如:
Thread thread=new Thread(r);
此時線程thread處於新建狀態,有了相應的
內存空間以及其它資源。
➢ Runnable (可運行)
⚫ runnable(可運行狀態)
➢ 此時線程已經啓動,處於線程的run()方法之
中。
➢ 此時的線程可能運行,也可能不運行,只要
CPU一空閒,立刻就會運行。
➢ 調用線程的start()方法可以使線程處於「可運
行」狀態。例如:
thread.start();
➢ Running(運行)
➢ Blocked (被阻塞)
⚫ blocked (被阻塞)
➢ 一個正在執行的線程因特殊緣由,被暫停執行,
進入阻塞狀態。
➢ 阻塞時線程不能進入隊列排隊,必須等到引發
阻塞的緣由消除,纔可從新進入排隊隊列。
➢ 引發阻塞的緣由不少,不一樣緣由要用不一樣的方
法解除。
⚫ sleep(),wait()是兩個經常使用引發線程阻塞的方法。
➢ Waiting (等待)
⚫ 等待阻塞 -- 經過調用線程的wait()方法,讓線
程等待某工做的完成。
➢ Timed waiting (計時等待)
➢ Terminated (被終止)
⚫ Terminated (被終止) 線程被終止的緣由有二:
➢ 一是run()方法中最後一個語句執行完畢而自
然死亡。
➢ 二是由於一個沒有捕獲的異常終止了run方法
而意外死亡。
➢ 能夠調用線程的 stop 方 法 殺 死 一 個 線 程
(thread.stop();),可是,stop方法已過期,
不要在本身的代碼中調用它。
其餘判斷和影響線程狀態的方法
➢join():等待指定線程的終止。
➢join(long millis):通過指定時間等待終止指定
的線程。
➢isAlive():測試當前線程是否在活動。
➢yield():讓當前線程由「運行狀態」進入到「就
緒狀態」從而讓其它具備相同優先級的等待線程
獲取執行權。
4.多線程調度:
– Java提供一個線程調度器來監控程序啓動後進入
可運行狀態的全部線程。線程調度器按照線程的
優先級決定應調度哪些線程來執行。
– 處於可運行狀態的線程首先進入就緒隊列排隊等
候處理器資源,同一時刻在就緒隊列中的線程可
能有多個。Java的多線程系統會給每一個線程自動
分配一個線程的優先級。
⚫ Java 的線程調度採用優先級策略:
➢ 優先級高的先執行,優先級低的後執行;
➢ 多線程系統會自動爲每一個線程分配一個優先級,缺省
時,繼承其父類的優先級;
➢ 任務緊急的線程,其優先級較高;
➢ 同優先級的線程按「先進先出」的隊列原則;
⚫ 下面幾種狀況下,當前運行線程會放棄CPU:
– 線程調用了yield() 或sleep() 方法;
– 搶先式系統下,有高優先級的線程參與調度;
– 因爲當前線程進行I/O訪問、外存讀寫、等待用
戶輸入等操做致使線程阻塞;或者是爲等候一
個條件變量,以及線程調用wait() 方法。
多線程併發執行中的問題:
◆多個線程相對執行的順序是不肯定的。
◆線程執行順序的不肯定性會產生執行結果的不
肯定性。
◆在多線程對共享數據操做時經常會產生這種不
肯定性。
5.線程同步:
多線程併發運行不肯定性問題解決方案:引入線
程同步機制,使得另外一線程要使用該方法,就只
能等待。
線程同步該部分將在下週詳細講述。
二:實驗部分:
實驗十六 線程技術
實驗時間 2017-12-8
1、實驗目的與要求
(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(); } } |
package threadPool; import javax.print.attribute.standard.RequestingUserName; class Lefthand extends Thread { //用thread的擴展類實現建立線程的方法,建立左手線程 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 extends Thread {//建立右手線程 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();//使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 right.start();//結果是兩個線程併發地運行;當前線程(從調用返回給 start 方法)和另外一個線程(執行其 run 方法)。 } }
用Runnable接口改造後的程序
package threadPool; import javax.print.attribute.standard.RequestingUserName; 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(); Runnable lefthand=new Lefthand(); Thread left=new Thread(lefthand);// Runnable沒有start這個方法,須要將Runnable的對象被Thread引用纔可在Thread中調用start方法 Runnable righthand=new Righthand(); Thread right=new Thread(righthand); left.start(); right.start(); } }
測試程序2:
l 在Elipse環境下調試教材625頁程序14-一、14-2 、14-3,結合程序運行結果理解程序;
l 在Elipse環境下調試教材631頁程序14-4,結合程序運行結果理解程序;
l 對比兩個程序,理解線程的概念和用途;
l 掌握線程建立的兩種技術。
程序的前兩個部分相同,在14-4中再也不贅述
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<>();//構造一個初始容量爲 10 的空列表。 //此接口的用戶能夠對列表中每一個元素的插入位置進行精確地控制。用戶能夠根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。 /** * 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);//將自建的swing組件放在居中的位置 JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "Start", event -> addBall()); addButton(buttonPanel, "Close", event -> System.exit(0));//將兩個組件註冊爲事件源並添加到buttonpanel中 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); }//用addbutton方法將兩個按鈕組合爲一個總體 /** * 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()); 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 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); t.start();//使得小球的移動成爲其中的一個子線程 } }
兩個程序的不一樣之處在於:第一個程序存在必定的缺陷,在該程序中,小球的運動軌跡的顯示只是程序的一部分,
當點擊start開始後,在程序運行過程當中,即顯示小球運動軌跡過程當中,並不能經過close或者右上角的關閉界面鍵來關閉程序;
第二個程序是對第一個程序的缺陷進行了優化,它將小球的顯示軌跡建立爲程序的一個子線程,這樣在小球顯示軌跡過程當中,可隨時關閉界面。
測試程序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);}//改變1號與3號線程的優先級 public void run( ) { for(int i=0; i<1000000; i++);//執行空循環,在該時間內1號與3號線程優先級的改變就已經起了做用 System.out.println(getName()+"線程的優先級是"+getPriority()+"已計算完畢!"); } }
測試程序4
l 教材642頁程序模擬一個有若干帳戶的銀行,隨機地生成在這些帳戶之間轉移錢款的交易。每個帳戶有一個線程。在每一筆交易中,會從線程所服務的帳戶中隨機轉移必定數目的錢款到另外一個隨機帳戶。
l 在Elipse環境下調試教材642頁程序14-五、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);//新建立一個帶入口參數的bank對象 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();//使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 } } }
綜合編程練習
編程練習1
(1) 用戶信息輸入界面以下圖所示:
(2) 用戶點擊提交按鈕時,用戶輸入信息顯示控制檯界面;
(3) 用戶點擊重置按鈕後,清空用戶已輸入信息;
(4) 點擊窗口關閉,程序退出。
import java.awt.EventQueue; import javax.swing.JFrame; public class Main { public static void main(String[] args) { EventQueue.invokeLater(() -> { DemoJFrame page = new DemoJFrame(); }); } }
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.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 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(); } }
3. 完善實驗十五 GUI綜合編程練習程序。
實驗總結;經過本週的學習我學到了線程的概念,而且掌握了線程建立的兩種技術,(1)用Thread類的子類建立線程(2)用Runnable()接口實現線程;
理解和掌握了線程的優先級屬性及調度方法,學到了線程的七種狀態。