多線程二:線程的基本操作,線程間的同步,synchronized,Happen-Before等

什麼是線程

線程是進程內的執行單元

例如 下面36417,就是進程

通過 命令,看到的,就是進程號37417裏的線程

jstack 36417

 

線程的狀態

線程的狀態,本來想找個圖片的,看到百度經驗這篇,說得挺好,挺詳細,就附上鍊接吧

https://jingyan.baidu.com/article/f79b7cb33886ef9144023ebf.html

 

線程的基本操作

創建線程的三種形式

1.直接繼承一個Thread類,重寫run方法

2.實現Runnable的接口,實現run方法,這種形式,是我平時工作中,使用最多的形式 3.創建一個Future接口的實現類 FutureTask,這種形式有返回值,並且可以拋出異常

需要注意的是,調用start方法,纔是執行線程,如果只是執行run方法,那麼程序會當成普通方法運行;

代碼如下

public class TestThread {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName());
                return 10;
            }
        });
        Thread thread = new Thread(futureTask);
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        Thread thread2 = new Thread(runnable);
        thread.start();
        thread1.start();
        thread2.start();
        try {
            thread.join();
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(futureTask.get());
    }
}

線程的一些常見方法:

Thread.stop() 線程終止;不推薦使用,它會釋放所有monitor監控,本來運行中的線程,或者運行一半,任務還沒有執行完成,也會被終止

public void Thread.interrupt() // 中斷線程 public boolean Thread.isInterrupted() // 判斷是否被中斷 public static boolean Thread.interrupted() // 判斷是否被中斷,並清除當前中斷狀態

suspend() ; 掛起;suspend()不會釋放鎖,如果加鎖發生在resume()之前 ,則死鎖發生 resume();繼續執行

join(); join(long millis);等待線程結束

yeild();謙讓;是指空出cpu當前的運行週期,等待下一輪cpu的時間片

守護線程

在後臺默默地完成一些系統性的服務,比如垃圾回收線程、JIT線程就可以理解爲守護線程

當一個Java應用內,只有守護線程時,Java虛擬機就會自然退出

Thread thredTest = new Thread(() ->{
            System.out.println(Thread.currentThread().getName());
        }) ;
				//標記爲守護線程
        thredTest.setDaemon(true);
        thredTest.start();

線程優先級

public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;

Thread high= new Thread(() ->{
            System.out.println(Thread.currentThread().getName());
        }) ; 
Thread low= new Thread(() ->{
            System.out.println(Thread.currentThread().getName());
        }) ; 
high.setPriority(Thread.MAX_PRIORITY); 
low.setPriority(Thread.MIN_PRIORITY); 
low.start();
high.start();

高優先級的線程更容易再競爭中獲勝,更容易獲得cpu的臨幸

基本的線程同步操作

synchronized

指定加鎖對象:對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。

//實例對象:同步代碼塊,鎖住的該類的實例對象
synchronized(this){
  
}
//class對象:鎖住的該類的類對象
synchronized(Test.class){
  
}

//任意實例對象:鎖住的是該創建的實例對象,下例是對lock對象加鎖
Object lock = new Obejct();
synchronized(lock){
  
}

對方法加鎖

//作用在方法上---實例方法:類的對象實例,鎖住的是該類的實例對象;
//相當於對當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。
public synchronized void test(){
	//........
}
//作用在方法上---靜態方法:鎖住的類的對象;相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。
public static synchronized void test1(){
  //.....
}

Object.wait() Obejct.notify()

首先wait方法和notify方法,是在synchronized關鍵詞中使用的,也就說,在執行方法之前,肯定是獲取到了對應的鎖操作;

舉例說明:A線程執行的時候,會釋放當前獲取到的鎖,讓出cpu的執行的時間,讓線程進入等待狀態,直到B線程獲取鎖的對象,執行對象的notify方法,纔會繼續執行;需要注意的時候,notify方法,不會釋放鎖,只有B線程執行完了,A線程纔會繼續獲取對象鎖,繼續執行

public static class T1 extends Thread{ 
  public void run(){
    synchronized (object) {
      System.out.println(System.currentTimeMillis()+":T1 start! "); 
      try {
        System.out.println(System.currentTimeMillis() +":T1 wait for object ");
        object.wait();
    } catch (InterruptedException e) {
      e.printStackTrace(); 
    }
      System.out.println(System.currentTimeMillis()+":T1 end!"); 
  }
}
                                      
public static class T2 extends Thread{ 
  public void run(){
  	synchronized (object) {
  		System.out.println(System.currentTimeMillis() +":T2 start! notify one thread");
  		object.notify(); System.out.println(System.currentTimeMillis()+":T2 end!"); 
      try {
  			Thread.sleep(2000);
  		} catch (InterruptedException e) { 
      }
  } }
}                 

最終的執行結果的順序,也是可以看出來的

1566523411000:T1 start!

1566523411000:T1 wait for object

1566523411000:T2 start! notify one thread

1566523411000:T2 end!

1566523411000:T1 end!

Happen-Before

程序順序原則:一個線程內保證語義的串行性

volatile規則:volatile變量的寫,先發生於讀,這保證了volatile變量的可見性

鎖規則:解鎖(unlock)必然發生在隨後的加鎖(lock)前

傳遞性:A先於B,B先於C,那麼A必然先於C

線程的start()方法先於它的每一個動作

線程的所有操作先於線程的終結(Thread.join())

線程的中斷(interrupt())先於被中斷線程的代碼

對象的構造函數執行結束先於finalize()方法

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章