JAVA多線程總結

一、多線程的基本知識

1、創建一個線程的兩個方法
  1. 通過繼承Thread類本身。
  2. 通過實現Runnable接口;
  通過繼承Thread類的方式有一定的侷限性,java中只支持單一一個類,一旦繼承了其他類就不能繼承Thread類了。
----通過繼承thread類創建線程

class MyThread extends Thread {   
    private int i = 0;
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);//獲取線程名稱;
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
                Thread myThread1 = new MyThread();     // 創建一個新的線程  myThread1  此線程進入新建狀態
                Thread myThread2 = new MyThread();     // 創建一個新的線程 myThread2 此線程進入新建狀態
                myThread1.start();                     // 調用start()方法使得線程進入就緒狀態
                myThread2.start();                     // 調用start()方法使得線程進入就緒狀態
            
        }
    }
}

----通過實現Runnable接口創建線程

class MyRunnable implements Runnable {
    private int i = 0;
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
                Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象
                Thread thread1 = new Thread(myRunnable); // 將myRunnable作爲Thread target創建新的線程
                Thread thread2 = new Thread(myRunnable);
                thread1.start(); // 調用start()方法使得線程進入就緒狀態
                thread2.start();  
        }
    }
}

2、Thread類的一些重要方法
1public void start()
使該線程開始執行;Java 虛擬機調用該線程的 run 方法。
public void run()
如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作並返回。
public final void setName(String name)
改變線程名稱,使之與參數 name 相同。
public final void setDaemon(boolean on)
將該線程標記爲守護線程或用戶線程。
public final void setPriority(int priority)
更改線程的優先級。
public final void join(long millisec)
等待該線程終止的時間最長爲 millis 毫秒。
public void interrupt()
中斷線程。
public final boolean isAlive()
測試線程是否處於活動狀態。
currentThread() 獲取當前線程
getName() 獲取當前線程名字
測試線程是否處於活動狀態。 上述方法是被Thread對象調用的。下面的方法是Thread類的靜態方法。
public static void yield()
暫停當前正在執行的線程對象,並執行其他線程。
只有與當前線程優先級相同或者更高的線程才能獲得執行機會。
public static void sleep(long millisec)
在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操作受到系統計時器和調度程序精度和準確性的影響。
public static boolean holdsLock(Object x)
當且僅當當前線程在指定的對象上保持監視器鎖時,才返回 true。
public static Thread currentThread()
返回對當前正在執行的線程對象的引用。
public static void dumpStack()
將當前線程的堆棧跟蹤打印至標準錯誤流。

3、Thread類的構造方法
  • Thread(Runnable threadOb,String threadName);// threadOb 是一個實現Runnable 接口的類的實例,並且 threadName指定新線程的名字。
  • Thread();
  • Thread(Rannable target);
  • Thread(String name) ;//繼承Thread類,並賦予名字;

4、設置線程的優先級
靜態常量 說明
static int MAX_PRIORITY            線程可以具有的最高優先級。相當於10
static int MIN_PRIORITY            線程可以具有的最低優先級。相當於1
static int NORM_PRIORITY            分配給線程的默認優先級。相當於5
5、線程的生命週期及狀態轉換


二、多線程的同步

1、線程的安全
     多線程的併發執行可以提高程序的效率,但當多個線程去訪問同一個資源是,將會引發一些安全問題。
     例如:多個窗口的售票系統,可能會在同一個時間賣出了同一張票。

2、同步代碼塊

Object lock =new Object();
synchronized(lock){
}
lock是一個鎖對象,默認情況下標誌位爲1,當線程執行同步代碼塊時會將鎖對象的標誌爲置爲0,阻止其他線程的調用。
等當前線程執行完同步代碼快後,新線程才能進入執行代碼塊內的內容。

實例
public class ThreadEx3{
    public static void main(String[] args) {
        Teacher t = new Teacher();
        new Thread(t, "窗口1").start();
        new Thread(t, "窗口2").start();
        new Thread(t, "窗口3").start();
    }
}
class Teacher implements Runnable {
    private int notes = 80;
   Object lock =new Object();
    public void run() {
        while (true) {
            synchronized(lock){

            if (notes > 0) {
            try {
                Thread.sleep(10); // 經過的線程休眠10毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---發出的票數"
                    + notes--);
        }//if
         }//while
        }//run()   
}//Runnable
       

3、同步方法

synchronized 返回值類型 方法名(){}
被synchronized修飾的方法在某一時刻只允許一個線程訪問,其他的線程都會發生堵塞。

實例
public class ThreadEx3{
    public static void main(String[] args) {
        Teacher t = new Teacher();
        new Thread(t, "窗口1").start();
        new Thread(t, "窗口2").start();
        new Thread(t, "窗口3").start();
    }
}
class Teacher implements Runnable {
    private int notes = 80;
    public void run() {
        while (true) {
            dispatchNotes(); // 調用售票方法
            if (notes <= 0) {
                break;
            }
        }
    }
    private synchronized void dispatchNotes() {//同步方法
        if (notes > 0) {
            try {
                Thread.sleep(10); // 經過的線程休眠10毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---發出的票數"
                    + notes--);
        }
    }
}



4、比較和弊端
    在同步方法中也有鎖的存在,只是在同步方法中的鎖不需要手動創建,這就在一點程度上保證了鎖的唯一性,同步方法被所以線程共享。
    弊端:
          線程每次執行同步代碼的時候都會判斷所得狀態,這回消耗大量的資源,效率低下。


三、多線程通信(等待/通知機制)
1、解決的問題
          輪詢的條件的可見性問題。多個線程將會按照一定順序流執行。
          所謂等待/通知機制,就是線程A在執行的時候,需要一個其他線程來提供的結果,但是其他線程還沒有告訴他這個結果是什麼,於是線程A開始等待,
當其他線程計算出結果之後就將結果通知給線程A,A線程喚醒,繼續執行。

      
2、用到的方法
void wait() wait()方法使得當前線程必須要等待,等到另外一個線程調用notify()或者notifyAll()方法。
void notify() notify()方法會喚醒一個等待當前對象的鎖的線程。
void notifyAll() 喚醒此同步鎖上調用wait()方法的所以線程
以上的三個方法的調用者都應是同步鎖對象.





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章