面試的時候總是會提及到這個關於線程的問題。(自己根據看到的資料和自己的理解想到的,大概會有不全的地方)
說到線程,首先說一下進程。
進程:運行中應用程序,享有系統資源(CPU等)。比如大家正在用的QQ,它就是一個進程。
線程:進程中的一段代碼,一個進程有多個線程。如何大家使用QQ這個進程,那麼你聽音樂和聊天就是兩個線程,從宏觀上看是同時執行的,實際上不是。這就是併發。
①線程是如何創建的:
1)通過繼承Thread類來實現,重寫run方法,通過new Thread()來創建線程的實例化對象,調用start()方法就可以啓動一個線程
2)通過實現Runnable接口是實現,重寫run方法,通過new Thread(new Runnable)來創建線程的實例化對象,調用start()方法啓動線程。
Thread類實現了Runnable接口。
②線程的狀態轉換
1)新建狀態,new實例化線程對象
2)就緒狀態 ,當調用start()方法之後,線程就進入就緒狀態
3)可運行狀態,這個狀態比較重要。當cpu分配資源的時候,就可以進入可運行狀態,執行run()方法。
可運行到就緒:時間片完了。或者是調用了yield()方法,也可以從可運行到就緒。
可運行到阻塞:調用sleep()方法,等待I/O。
可運行到死亡:程序在運行過程中遇到異常,調用stop()和destroy()方法。
sleep()和wait()方法的區別:
sleep是佔用cpu資源,但是不工作,其他線程不能佔用該CPU,OS會認爲該線程正在工作,不會讓出系統資源
wait是到等待池進行等待,讓出系統資源。
③多線程
多線程,顧名思義就是多個線程同時運行。
涉及到的問題有 同步、死鎖
比如線程A和線程B,要進行通信,並且對數據結構進行讀寫,比如鏈表。線程A要對鏈表進行讀的操作,線程B要對鏈表進行寫的操作,那麼可能造成數據不安全。
應該要實現什麼呢?當線程A對鏈表進行操作的時候,線程B不可以鏈表進行操作,只有到線程A釋放了鎖之後,別的線程纔可以進行操作
1)同步互斥:多個併發執行的線程在在某一個時間段內只能有一個線程對數據進行操作。
同步的方法:
1>synchronized修飾方法
2>synchronized修飾代碼塊
3>特殊變量域 volatile
4>ThreadLocal類
比如一個例子:
火車票賣票,有兩個窗口,如何實現數據共享
package
com.ljq.test;
/**
* 使用Runnable接口模擬4個售票窗口共同賣100張火車票的程序
*
* 共享數據,4個線程共同賣這100張火車票
* @author jiqinlin
*
*/
publicclass RunnableTest {
publicstaticvoid main(String[] args) {
Runnable runnable=new MyThread();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
public static class MyThread implements Runnable{
//車票數量
private int tickets=100;
publicvoid run() {
while(tickets>0){
System.out.println(Thread.currentThread().getName()+"賣出第【"+tickets--+"】張火車票");
}
}
}
}
實際工作中,幾乎所有的多線程應用都用實現Runnable這種方式。