一、多線程的基本知識
1、創建一個線程的兩個方法
- 通過繼承Thread類本身。
- 通過實現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、設置線程的優先級
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()方法的所以線程 |
以上的三個方法的調用者都應是同步鎖對象.