標籤:width java live exception java多線程 row 操作 sum tar
1、為什麼要使用多線程?多線程的優點?
提高CPU的利用率
2、什麼是多線程?
3、Java實現多線程編程的兩種方式?
a、繼承Thread類
|
public class MyThread01 extends Thread {
@Override
public void run() {
super.run();
System.out.println("MyThread01");
}
public static void main(String[] args){
MyThread01 myThread01 = new MyThread01();
myThread01.start();
System.out.println("運行結束");
}
}
|
|
運行結束
MyThread01 |
|
多次調用start(),拋異常 |
public class MyThread01 extends Thread { @Override public void run() { super.run(); System.out.println("MyThread01"); } public static void main(String[] args){ MyThread01 myThread01 = new MyThread01(); myThread01.start(); myThread01.start(); System.out.println("運行結束"); } }
|
|
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at com.season.testthread.MyThread01.main(MyThread01.java:13)
MyThread01 |
b、實現Runnable介面
public class MyRunnable01 implements Runnable { @Override public void run() { System.out.println("MyRunnable01 run()....."); } public static void main(String[] args){ Runnable runnable = new MyRunnable01(); Thread thread = new Thread(runnable); thread.start(); System.out.println("main()....."); } }
|
|
main().....
MyRunnable01 run()..... |
4、兩種方式的對比?
Thread類本身實現了Runnable介面;
使用Thread類方式建立線程,最大的局限是不支援多繼承
5、start() 和 直接調用run() 有什麼異同?
Thread.java類中的 start() 通知“線程規劃器”此線程已經準備就緒,等待調用線程對象的 run()。run()是由調用線程執行,必須等待 run() 代碼執行完成才能執行後面代碼,不具有非同步效果。
6、非安全執行緒?
多個線程對同一對象中的同一執行個體變數進行操作時會出現值被更改、值不同步的情況,進而影響程式的執行流程。
|
(1)不共用資料情況 |
|
public class MyThread02 extends Thread {
private int count = 5;
public MyThread02(String name){
this.setName(name);
}
@Override
public void run() {
super.run();
while (count > 0){
count--;
System.out.println("由 " + Thread.currentThread().getName() + " 計算,count=" + count);
}
}
public static void main(String[] args){
MyThread02 a = new MyThread02("a");
MyThread02 b = new MyThread02("b");
MyThread02 c = new MyThread02("c");
a.start();
b.start();
c.start();
}
}
|
|
由 a 計算,count=4
由 a 計算,count=3
由 a 計算,count=2
由 a 計算,count=1
由 a 計算,count=0
由 c 計算,count=4
由 c 計算,count=3
由 c 計算,count=2
由 c 計算,count=1
由 c 計算,count=0
由 b 計算,count=4
由 b 計算,count=3
由 b 計算,count=2
由 b 計算,count=1
由 b 計算,count=0 |
|
(2)共用資料情況 |
|
public class MyThread03 extends Thread {
private int count = 5;
@Override
public void run() {
super.run();
while (count > 0){
count--;
System.out.println("由 " + Thread.currentThread().getName() + " 計算,count=" + count);
}
}
public static void main(String[] args){
MyThread03 myThread03 = new MyThread03();
Thread a = new Thread(myThread03, "a");
Thread b = new Thread(myThread03, "b");
Thread c = new Thread(myThread03, "c");
Thread d = new Thread(myThread03, "d");
Thread e = new Thread(myThread03, "e");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
|
|
由 c 計算,count=3
由 c 計算,count=2
由 c 計算,count=1
由 c 計算,count=0
由 a 計算,count=3 |
7、怎麼解決非安全執行緒問題?
使用 synchronized 關鍵字:當一個線程要執行同步方法裡面的代碼時,線程首先嘗試去拿這把鎖,如果能拿到,這個線程就可以執行synchronized 裡面的代碼。如果拿不到,那麼這個線程就會不斷嘗試拿這把鎖,直到拿到為止,而且是有多個線程同時去爭搶這把鎖。
8、API
|
currentThread() 傳回碼段正在被哪個線程調用的資訊。 |
|
isAlive() 判斷當前線程是否處於活動狀態(線程已經啟動且尚未終止)。 |
|
sleep() 在指定的毫秒內讓當前“正在執行的線程”休眠(暫停執行) |
|
getId() 取得線程的唯一標識 |
|
yield() 放棄當前的CPU資源,將它讓給其他的任務去佔用CPU執行時間。但放棄的時間不確定,有可能剛剛放棄,馬上又獲得CPU時間片。 |
9、怎麼停止線程?
1)、使用退出標誌,使線程正常退出,也就是當run方法完成後線程終止。
2)、使用 stop() 強行終止線程,不推薦使用這種方法,因為 stop 和 suspend 及 resume 一樣,都是作廢到期的方法,使用它們可能產生不可預料的結果。如果強行讓線程停止則可能使一些請理性的工作得不到完成。另外一個情況就是對鎖定的對象進行了“解鎖”,導致資料得不到同步處理,出現資料不一致問題。
3)、使用 interrupt() 中斷線程。
|
interrupt() 僅僅是在當前線程中打了一個停止標記,並不是真的停止線程。
this.interrupted() 測試當前線程是否已經中斷狀態,執行後具有將狀態標識置清除為false的功能。當前線程是指運行 this. Interrupted() 的線程。interrupted() 具有清除狀態的功能,所以第二次調用interrupted() 傳回值是false。
this.isInterrupted() 測試線程Thread對象是否已經是中斷狀態,但不清除狀態標識。 |
|
a、能停止的線程——異常法 |
|
public class MyThread04 extends Thread {
@Override
public void run() {
for(int i = 0; i < 500000; i++){
if(this.interrupted()){
System.out.println("已經是停止狀態,立即退出!");
break;
}
System.out.println("i = " + (i + 1));
}
System.out.println("for下面語句運行,線程並未停止。");
}
public static void main(String[] args) {
try {
MyThread04 myThread04 = new MyThread04();
myThread04.start();
Thread.sleep(2000);
myThread04.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch{}...");
e.printStackTrace();
}
System.out.println("main() end ....");
}
}
|
|
i = 207023
main() end ....
已經是停止狀態,立即退出!
for下面語句運行,線程並未停止。 |
|
上面的樣本雖然停止了線程,但是如果for下面還有語句,還是會繼續啟動並執行。
該如何解決語句繼續啟動並執行問題呢? |
|
package com.jvm.thread;
public class MyThread04 extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("已經是停止狀態,立即退出!");
throw new InterruptedException();
}
System.out.println("i = " + (i + 1));
}
System.out.println("for下面語句運行,線程並未停止。");
} catch (InterruptedException e) {
System.out.println("進入 MyThread04 類的 run() 的catch{}...");
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
MyThread04 myThread04 = new MyThread04();
myThread04.start();
Thread.sleep(2000);
myThread04.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch{}...");
e.printStackTrace();
}
System.out.println("main() end ....");
}
}
|
|
i = 220112
i = 220113
main() end ....
已經是停止狀態,立即退出!
進入 MyThread04 類的 run() 的catch{}...
java.lang.InterruptedException
at com.jvm.thread.MyThread04.run(MyThread04.java:10) |
|
|
|
b、使用 return 停止線程
interrupt() 與 return 結合使用 |
|
package com.jvm.thread;
public class MyThread05 extends Thread {
@Override
public void run() {
while(true){
if(this.isInterrupted()){
System.out.println("停止了!");
return;
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread05 myThread05 = new MyThread05();
myThread05.start();
Thread.sleep(2000);
myThread05.interrupt();
}
}
|
|
|
10、怎麼暫停線程?
暫停線程意味著此線程還可以恢複運行。在java多線程中,可以使用suspend() 暫停線程,使用 resume() 恢複線程的執行。
suspend 與 resume 方法的缺點——獨佔
suspend 與 resume 方法的缺點——不同步
11、線程的優先順序
在作業系統中,線程可以劃分優先順序,優先順序較高的線程得到的CPU資源較多,也就是CPU優先執行優先極高的縣城對象中的任務。
設定線程優先順序有助於幫組“線程規劃器”確定下一次選擇哪一個線程來優先執行。
優先順序具有隨機性。
12、守護線程
在Java線程中有兩種線程,一種是使用者線程,另一種是守護線程。
當進程中不存在非守護線程了,則守護線程自動銷毀。典型的守護線程就是記憶體回收線程。
(1)Java多線程編程核心——Java多線程技能