Java-多線程基本
一 相關的概念
程序:是一個正在執行中的程式
每個程序都有一個執行的順序,該順序是一個執行路徑,或者叫一個控制單元
線程:就是程序中的一個獨立的控制單元,線程在控制着程序的執行
注意 :
一個程序至少有一個線程
Java VM啟動的時候會有一個程序java.exe
該程序中至少一個線程負責java程式的執行,并且這個線程執行的代碼在main方法中
該線程稱為主線程
JVM啟動不止一個線程,還有負責垃圾回收機制的線程
二 自己定義建立線程
須要用到Thread類
建立方法一:
1.定義類繼承自Thread
2.複寫Thread中的run方法
3.調用線程的start方法,該方法有兩個作用:啟動線程。調用run方法
建立方法二:
1.定義類實作Runnable接口
2.覆寫Runnable接口中的run方法
3.通過Thread類建立線程對象
4.将Runnable接口的子類對象作為實際參數傳遞給Thread類的構造函數:
原因是自己定義的run方法所屬的對象是Runnable接口的子類對象
是以要讓線程去指定對象的run方法。就必須明白run方法的所屬對象
5.調用Thread類的start方法開啟線程并調用Runnable接口子類的run方法
兩種方式的差别:
方法二實作方式的優點:避免了單繼承的局限性,建議使用實作的方式
多線程的特性:随機性。因為cpu的分時排程規則(在某一個時刻,cpu隻執行一個程式,cpu在執行過程中做着高速的切換),至于執行的時間,cpu說的算
對象調用run和start的差别:
start:開啟線程并執行該線程的run方法
run:不過對象調用方法,并且線程建立了,并沒有執行
多線程的執行狀态:
建立,執行,消亡,堵塞。當機
例如以下圖:
多線程經常使用的方法:
static Thread currentThread()擷取目前線程對象
getName()擷取線程名稱。線程名稱預設格式為Thread-0(1,2,3…..)
setName或者構造函數能夠設定線程名稱
三 多線程的安全問題:
解決線程操作資料時的時間差問題須要用到
1。同步代碼塊
synchronized(對象鎖)
{
須要同步的代碼。
}
2,同步函數
就是将synchronized關鍵字加到函數上
public synchronized void Test()
{
}
怎樣找出線程的安全隐患:
1.明白哪些代碼是多線程執行代碼
2.明白共享的資料
3.明白多線程執行代碼中哪些語句是操作共享資料的
三 鎖
鎖:
鎖就是一個對象
同步函數的鎖死this,
靜态同步函數的鎖是該方法所在類的位元組碼檔案對象。類名.class對象:靜态方法中不能夠定義this,靜态方法進入記憶體,記憶體中還沒有本類的對象
可是一定有該類相應的位元組碼檔案對象,類名.class。該對象的類型是class
死鎖:兩個線程互相争奪鎖的情況
以下是一個面試題:寫一個死鎖的Demo
class Test implements Runnable
{
private boolean flag;
Test(boolean p_flag)
{
this.flag = p_flag;
}
public void run()
{
if (flag)
{
while (true)
{
synchronized(MyLock.locka)
{
System.out.println("if locka");
synchronized(MyLock.lockb)
{
System.out.println("if lockb");
}
}
}
}
else
{
while (true)
{
synchronized(MyLock.lockb)
{
System.out.println("if lockb");
synchronized(MyLock.locka)
{
System.out.println("if locka");
}
}
}
}
}
}
//鎖對象
class MyLock
{
static Object locka = new Object();
static Object lockb = new Object();
}
class TestDemo
{
public static void main(String[] args)
{
Thread t1 = new Thread(new Test(true));
Thread t2 = new Thread(new Test(false));
t1.start();
t2.start();
}
}
四 多線程與單例設計模式:
class Singel
{
private static Singel s = null;
private Singel();
public static Singel getInstance()
{
//雙重推斷能夠解決效率低的問題
if (null == s)
{
//synchronized關鍵字比起在函數上同步更加高效
synchronized(Singel.class)//使用的本類檔案的鎖
{
if (null == s)
{
s = new Singel();
}
}
return s;
}
}
}