概念
區分線程和進程
進程——>.exe程序,進程是受系統操作管理的基本單元
線程:可以理解成是在進程中獨立運行的子任務。
使用多線程的優點:可以最大限度地利用CPU的空閒時間來處理其他任務
使用多線程也就是在使用異步。
使用多線程
實現方式
1.繼承Thread類
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("run方法的打印:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
MyThread myThread = new MyThread();
myThread.start();
}
}
}
MyThread類中的run 方法比較晚,這就是說明使用多線程技術時,代碼的運行結果與代碼執行順序或調用順序無關
線程是一個子任務,CPU以不確定的方式,或者說是以隨機的時間來調用線程中的run方法.
a.myThread.start(),方法是通知“線程規劃器”此線程已經準備就緒,等待調用線程對象的run()方法。
b.myThread.run()就不是異步執行了,而是同步,那麼此此線程對象並不是交給“線程規劃器”處理,而是由main主線程來調用run()方法,也就是必須等run()方法中的代碼執行後纔可以執行後面的代碼。
2.實現Runnable接口
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("運行中!");
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
System.out.println("運行結束!");
}
}
其中Thread類實現了Runnable接口,Java語言的特點就是單繼承,所以爲了支持多繼承,完全可以實現Runnable接口的方法
Thead.java類也實現了Runnalbe接口
那也就意味着構造函數Thead(Runnable targer) 不光可以傳入Runnable接口的對象,還可以傳入一個Thread 類的對象,這樣做完全可以將一個Thread對象中的run方法交由其他線程調用
3.isAlive()
方法是判斷當前的線程是否處於活動狀態
什麼是活動狀態,就是線程已經啓動且尚未終止。線程處於正在運行或者準備開始運行的狀態,就認爲線程是“存活”的。
4.sleep()
方法sleep()的作用就是在指定的毫秒數內讓當前“正在執行的線程”休眠(暫停這個線程)。
這個正在執行的線程是指this.currentThread()返回的線程。
Thread.sleep(2000);
5.停止線程
在Java 中有三種方法可以終止正在運行的線程
- 1.使用推出標緻,是線程正常退出,也就是當run方法完成後線程終止。
- 2.使用stop方法強行終止線程,但是不推薦這個方法,因爲stop和suspend及resume一樣,都是作廢的方法,使用他們可能產生不可預料的結果。
- 3.使用interrupt
1.this.interrupted();測試當前線程是否已經是中斷狀態,執行後具有將狀態標誌置清除爲false的功能。
2.this.isInterrupted():測試線程Thread對象是否已經是中斷狀態,但不清除標誌。
能停止的線程——異常法
public class ExceptionThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 5000000; i++) {
if (this.interrupted()) {
System.out.println("已經是停止狀態了!我要退出了!");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
System.out.println("我再for下面!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
ExceptionThread exceptionThread = new ExceptionThread();
exceptionThread.start();
try {
Thread.sleep(1000);
exceptionThread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
運行結果如下
在沉睡中停止
a.先睡後停止
public class SleepThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("run begin");
try {
Thread.sleep(2000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止!進入catch"+this.isInterrupted());
e.printStackTrace();
}
}
}
public class SleepRun {
public static void main(String[] args) {
SleepThread sleepThread = new SleepThread();
sleepThread.start();
try {
Thread.sleep(200);
sleepThread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
運行結果
b.先停止後睡
public class LastSleepThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 10000; i++) {
System.out.println("i=" + (i + 1));
}
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("先停止,在遇到了sleep! 進入catch!");
e.printStackTrace();
}
}
}
public class LastSleepRun {
public static void main(String[] args) {
try {
LastSleepThread lastSleepThread = new LastSleepThread();
lastSleepThread.start();
lastSleepThread.interrupt();
System.out.println("end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
能停止的線程——暴力停止
使用stop()方法停止線程
stop()已經作廢,因爲如果強制讓線程停止則有可能使一些請理性的工作得不到完成。另外一個情況就是對鎖定的對象進行了“解鎖”,導致數據得不到同步的處理,出現數據不一致的問題。
使用return停止線程
public class ReturnThread extends Thread {
@Override
public void run() {
while (true){
if(this.isInterrupted()){
System.out.println("停止了!");
return;
}
System.out.println("timer="+System.currentTimeMillis());
}
}
}
public class ReturnRun {
public static void main(String[] args) {
try {
ReturnThread returnThread = new ReturnThread();
returnThread.start();
Thread.sleep(2000);
returnThread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
6.暫停線程
暫停線程意味着此線程還可以恢復運行。在java中使用suspend()方法暫停線程,使用resume()方法恢復線程的執行。
suspend與resume方法的缺點——獨佔,極易造成公共的同步對象的獨佔,使得其他線程無法訪問公共同步對象。
7.yield方法
yield()方法的作用是放棄當前的CPU資源,將它讓給其他的任務去佔用CPU執行時間。當放棄的時間不確定,有可能剛剛放棄,馬上又獲得CPU時間片。
8.線程的優先級
使用線程的優先級使用setPriority()方法。
在Java中,線程的優先級分爲1-10這10個等級。
線程優先級的繼承特性。
線程的優先級具有繼承性,比如A線程啓動B線程,則B線程的優先級與A是一樣的。
優先級具有隨機性。
9.守護線程
java線程分爲兩種線程,一種是用戶線程,另外一種是守護線程。
什麼是守護線程?守護線程是一種特殊的線程,他的特性有陪伴的意義,當進程中不存在非守護線程了,則守護線程自動銷燬。
典型的守護線程就是垃圾回收線程。