創建線程的三種方式
1、繼承Thread;
static class MyThread extends Thread{@Overridepublic void run() {//do something...}
}
public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread ();thread.start();
}
2、實現Runnable接口(該接口無返回值);
static class MyRunnable implements Runnable {public void run() {//do something...}
}
public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new MyRunnable(),"MyRunnable");thread.start();
}
3、實現Callable接口(該接口有返回值,在之前的SpringMvc中有提到過)
static class MyCallable implements Callable<String> {public String run() {String result = "";//do something...return result;}
}
public static void main(String[] args) throws InterruptedException {FutureTask<String> task = new FutureTask<String>(MyCallable);new Thread(task).start();//獲取結果值String result = task.get();
}
jdk也提供了通過了創建線程池的方式去創建線程,但是線程池底層及時通過去創建Thread對象創建線程的,所以只有這三種方式
線程共享協作
先來認識一下 synchronized?這個關鍵字,這個在大部分網上都能找到相關的資料,這里就簡單的說明一下:
synchronized鎖也叫內置鎖,可用于兩種情況,1、修飾在靜態方法上,即類鎖;2、修飾在普通方法上或者synchronized代碼塊,即對象鎖。示例如下:
//類鎖:
public synchronized static void function(){//do something...}
//對象鎖:
//修飾方法,同一個對象同一時刻只能有一個線程執行該方法
public synchronized void function(){...}
//synchronized 代碼快
public void function(){synchronized(this){//鎖住當前對象(this可替換成其他對象,即只有執行完當前代碼塊后,才能釋放,同一時刻,當前線程獲取到對象鎖后,才能執行,其他線程進入等待阻塞狀態)//...}
}
volatile關鍵字:適合于只有一個線程寫,多個線程讀的場景,因為它只能確保可見性。
ThreadLocal:可以參考ThreadLocal詳解,這篇講的挺詳細的
wait(),notify()/notifyAll()
wait():即等待通知,作用于對象上,當前線程調用對象的wait()方法會使進入阻塞狀態并釋放當前持有鎖,需和synchronized一起使用,等待當前對象調用notify/notifyAll()方法之后,需重新競爭到鎖后,方可繼續執行,未被喚醒則一直等待。
notify()/notifyAll():作用于對象上,用來喚醒阻塞狀態的wait()方法,需和synchronized一起使用,執行完后,需繼續執行后面的程序才能釋放當前持有鎖,一般將該方法放于最后。
public void function () {//...synchronized (this) {//do something...notify();}//...
}
notify()喚醒隨機一個wait()方法阻塞線程,而notifyAll()則是喚醒所有的wait()阻塞線程,wait()被喚醒后,需重新去競爭鎖,才能繼續執行。
wait(long mills):即等待超時方法,即等待mills毫秒后,如若時間到后未收到喚醒,則繼續執行后面的代碼。
long overtime = now+T;
long remain = T;//等待的持續時間
while(result不滿足條件&& remain>0){wait(remain);remain = overtime – now;//等待剩下的持續時間
}
return result;
join()
可以將并行執行的線程變成串行執行模式,可以理解為插隊執行,以下為示例:
static class Worker implements Runnable{private Thread thread;public Worker(Thread thread) {this.thread = thread;}public void run() {try {System.out.println(thread.getName()+"start join...");thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" terminte..." + System.currentTimeMillis());}}public static void main(String[] args) throws InterruptedException {System.out.println(Thread.currentThread().getName()+" start..." + System.currentTimeMillis());Thread main = Thread.currentThread();Thread thread1 = new Thread(new Worker(main),"join1");Thread thread2 = new Thread(new Worker(thread1),"join2");Thread thread3 = new Thread(new Worker(thread2),"join3");thread1.start();thread2.start();thread3.start();System.out.println(Thread.currentThread().getName()+" sleep...");try {Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+" end...");} catch (InterruptedException e) {e.printStackTrace();}}
執行結果為:
main start...1616734827339
main sleep...
mainstart join...
join2start join...
join1start join...
main end...
join1 terminte...1616734828340
join2 terminte...1616734828340
join3 terminte...1616734828340
即在當前線程中調用其他線程的join()方法后,其他線程就會進去到阻塞狀態,只有等待當前線程執行完成后,其他線程才能繼續執行,由并行變成串行;
join()方法里面也是由wait()方法去處理的