1. 程式人生 > >李曉菁201771010114《面向物件程式設計Java》第十六週學習總結

李曉菁201771010114《面向物件程式設計Java》第十六週學習總結

一:理論知識

1.執行緒的概念:

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

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

(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()方法的實現。

–在適當的時候啟動執行緒。

由於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 方法)。 
         }
    }
threadPool

用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();
         }
    }
threadpool

測試程式2

l 在Elipse環境下除錯教材625頁程式14-1、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);
   }
}
ball
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); }
}
bounceThreade
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)
      {
      }
   }
}
bounce

彌補缺陷後的程式(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();//使得小球的移動成為其中的一個子執行緒
   }
}
bounceThread

兩個程式的不同之處在於:第一個程式存在一定的缺陷,在該程式中,小球的運動軌跡的顯示只是程式的一部分,

當點選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()+"已計算完畢!");
    }
}
race

測試程式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;
   }
}
bank
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 方法。 
      }
   }
}
UnsynchBankTest

 

 

綜合程式設計練習

程式設計練習1

  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();
        });
    }
}
main
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();
    }
}
DemoJFrame
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);
    }
}
WinCenter

點選提交後在控制檯的顯示:

點選重置後:

 

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();

         }

    }
ThreadText

 

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

實驗總結;通過本週的學習我學到了執行緒的概念,並且掌握了執行緒建立的兩種技術,(1)用Thread類的子類建立執行緒(2)用Runnable()介面實現執行緒;

理解和掌握了執行緒的優先順序屬性及排程方法,學到了執行緒的七種狀態。