多線程:
程序運行時:啓動了兩個線程:
Main線程:調用main方法,執行main方法。
GC線程:在main線程運行時運行,回收程序運行之中的垃圾。
線程:一條執行路徑。多線程完成多個功能併發併發執行的效果。
多線程之間亂系執行、同一線程內部順序執行的。
寫多線程:
1. 繼承自Thread類,重寫run方法。然後用Thread的start方法啓動線程。
2. 實現Runnable接口,實現run方法。然後用Thread的start方法啓動線程。
兩種方式的區別:
1. 第一種使用簡單。
2. 第二種不受java單繼承的限制。一般來說,都是用第二種。
線程中常用的方法:線程中的已過時方法禁止使用。其他類中的過時方法不建議使用。
1. start:啓動一個新線程。啓動之後jvm會自動執行run方法。
2. run:線程啓動之後執行的方法。
3. setName、getName:自動命名,Thread-0,1…
4. currentThread:得到當前運行的線程。
5. getPriority()、setPriority 得到和設置當前線程的優先級。優先級1-10,如果不指定默認是5. 理論上,誰優先級高,誰被cpu調度的可能性就大。但是優先級低的並不是不執行。資源不足的時候纔有效果。
6. setDaemon:將線程置爲守護線程。只能在線程start之前調用。一般用於爲其他線程提供服務,比如GC。守護線程會隨着其他非守護線程的結束而結束。isDaemon可以用於判斷某個線程是否是守護線程。
7. sleep:讓當前線程停止執行(休眠)一段時間。
8. join:如果在A線程中B線程join進來,則現在執行B的內容,直到B執行完畢才繼續執行A。比如A是顯示數據 B是收集收據。
9. yield:讓位:讓出執行權,和其他線程爭奪資源,誰拿到cpu時間片誰執行。
線程的狀態圖:說明 run方法結束,新線程結束。
package day16; import java.util.ArrayList; import java.util.Vector; public class Bank { public static void main(String[] args) { // 創建一個賬戶 Account account = new Account(); // 你和女朋友操作同一個賬戶 Person1 you1 = new Person1(account); Person1 yourGF1 = new Person1(account); Thread thYou1 = new Thread(you1); Thread thYourGF1 = new Thread(yourGF1); // 你和女朋友同時去取錢。 thYou1.start(); thYourGF1.start(); // 存錢線程 Person2 you2 = new Person2(account); Person2 yourGF2 = new Person2(account); Thread thYou2 = new Thread(you2); Thread thYourGF2 = new Thread(yourGF2); thYou2.start(); thYourGF2.start(); try { Thread.sleep(5000);// 確保賬戶操作完畢 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最終賬戶餘額:"+account.balance); } } class Account{ private ArrayList list; private Vector v ; public int balance = 2000; private Object obj1 = new Object(); // private Object obj2 = new Object(); // 取款 public /*synchronized*/ void withdraw(){// 同一時間只能有一個線程訪問。 synchronized (obj1) { int temp = balance; temp = temp - 800; try { Thread.sleep(1000);// 模擬網絡延遲。 } catch (InterruptedException e) { e.printStackTrace(); } balance = temp; System.out.println(Thread.currentThread().getName()+"取款"); // while(true){} } } // 存款 public /*synchronized*/ void deposit(){// 同一時間只能有一個線程訪問。 synchronized (obj1) { int temp = balance; temp = temp + 800; try { Thread.sleep(1000);// 模擬網絡延遲。 } catch (InterruptedException e) { e.printStackTrace(); } balance = temp; System.out.println(Thread.currentThread().getName()+"存款"); } } } class Person1 implements Runnable{ // 人要自己的賬戶。 private Account account ; public Person1(Account account){ this.account = account; } @Override public void run() { account.withdraw(); } } class Person2 implements Runnable{ // 人要自己的賬戶。 private Account account ; public Person2(Account account){ this.account = account; } @Override public void run() { account.deposit(); } }
線程相關的常用類:
1. Timer:定時器、調度器、計時器。
2. TimerTask:定時任務。
線程間的同步:本質:把異步轉化爲同步,把並行轉爲串行。
方式:
1. 同步語句塊:synchronized(obj){}
2. 同步方法:在方法前加synchronized修飾符,拿到的仍然是本類對象的鎖。
難點:不容易測出來。
對象鎖:每個對象都有一把鎖。同步鎖、互斥鎖
package day16; import java.awt.BorderLayout; import java.util.Timer; import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import com.sun.awt.AWTUtilities; public class Logo extends JFrame{ /** logo下標 **/ private int niIndex = 1; /** 顯示圖片內容的標籤 **/ private JLabel lbShow; /** 計時器 **/ private Timer timer; public Logo(){ JPanel pnBasic = new JPanel(); pnBasic.setLayout(new BorderLayout()); lbShow = new JLabel(); pnBasic.add(lbShow,BorderLayout.CENTER); lbShow.setIcon(new ImageIcon("fff/role1/1.png")); setContentPane(pnBasic); setTitle("歡迎界面"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(200,200,410,320); // 透明 setUndecorated(true); AWTUtilities.setWindowOpaque(this, false); setVisible(true); // 定義定時器 timer = new Timer(); // 1.重複執行的任務 2.延遲多長時間執行 3.執行頻率 timer.schedule(new LogoMonitor(),1000,500); } private class LogoMonitor extends TimerTask{ @Override public void run() { if(niIndex<7){ niIndex++; lbShow.setIcon(new ImageIcon("fff/role1/"+niIndex+".png")); }else{ timer.cancel(); dispose(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("進入主界面"); } } } public static void main(String[] args) { new Logo(); } }