Java高併發1-建立線程的三種方式、虛假喚醒、native關鍵字

1、建立多線程的兩種方式

1.繼承Thread類,重寫run方法

2.實現Runnable接口,重寫run方法

3.直接上代碼

package com.ruigege.threadFoundation1;

public class MyThreadExtendsType extends Thread {
	
	@Override
	public void run() {
		System.out.println("這是一個繼承Thread類的多線程表示方法");
	}

}
package com.ruigege.threadFoundation1;

public class MyThreadImplementsRunnable implements Runnable{
	@Override
	public void run() {
		System.out.println("這是一個實現Runable接口的多線程");
	}
	
}
package com.ruigege.threadFoundation1;


public class MultiBuildThreadTest {
	public static void main(String[] args) {
		//使用繼承Thread的類的方式來進行多線程建立
		MyThreadExtendsType thread1 = new MyThreadExtendsType();
		thread1.start();
		//使用實現Runnable接口的方式進行多線程建立
		Thread thread2 = new Thread(new MyThreadImplementsRunnable());
		thread2.start();
		
		
	}
}

4.兩者之間的差異

  • (1)調用方式:繼承的時候直接建立新的實例,而後調用run方法;實現接口的方式,要建立一個實例做爲參數做爲Thread的構造方法中,再進行調用
  • (2)擴展性:繼承只能單繼承,耦合度高;實現的方式就不同了,耦合度小
  • (3)繼承的好處,就是在實例中直接使用this關鍵字就可使用該線程,而不須要調用Thread.currendThread()方法來獲取實例。能夠在子類中添加成員變量,若是使用了Runnable方式,那麼只能使用主線程中被聲明爲final的變量
  • (4)兩種方式都有一個弊端,就是沒有返回值,下面再介紹一種

5.第三中方式,使用FuntureTask

package com.ruigege.threadFoundation1;

import java.util.concurrent.Callable;

public class MyThreadImplementsCallable implements Callable<String> {
	@Override
	public String call() throws Exception{
		System.out.println("使用FutureTask的方式來行建立多線程");
		return "建立好了";
	}
	

}
package com.ruigege.threadFoundation1;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MultiBuildThreadTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException{
		//使用Callable和FutureTask來建立多線程
		FutureTask<String> futurnTask = new FutureTask<>(new MyThreadImplementsCallable());
		Thread thread3 = new Thread(futurnTask);
		
		thread3.start();
		System.out.println(futurnTask.get());	
	}
}

1.1

6.知識掃盲

  • 系統進行資源調度和內存分配的基本單位------進程
  • 線程就是進程的一個執行路徑
  • 內部的機制:一個進程中有一個或者多個線程,進程中的堆和方法區線程內公用。線程中的棧和程序計數器,本身獨有。
    1.2
  • 程序計數器是用於記錄線程當前要執行的地址(原理:CPU是分片加載執行的,一片執行完,要記住下一次從哪裏執行)

執行native方法,pc計數器是undefined地址;執行Java代碼的時候纔是原定義java

  • 堆是何時分配的?進程建立的時候就會分配一塊內存區域給堆。
  • 就緒狀態:調用了start()方法以後,並無立刻執行線程,這個就緒狀態就是獲取了除了CPU之外的全部的資源的狀態,一旦獲取了CPU資源後,纔會開始真正執行。

2、native關鍵字

  • JNI(Java Native Inteface)
  • 做用:使用在方法名稱的前面,意味着這個方法,並非使用Java來編寫,而是由其餘語言來編寫的,這個native就是聲明這是個原生函數,具體是由C/C++來實現的而且會編譯成dll文件,供Java來進行調用
  • 使用這種機制的緣由:Java並不是完美,在一些要求高性能的場景中,每每C/C++語言會更加快,因而native的出現可以很好的解決這個問題。
  • 實現的步驟:(1)首先使用native關鍵字來聲明這個方法是原生方法;
    (2)使用Javah生成一個相似於頭文件的文件;(3)使用C/C++來編寫這個函數,注意其中要引用第二步中產生的頭文件(這個頭文件又引用了jni.h這個頭文件);(4)將這個寫好的C碼編譯成一個動態連接庫文件;
    (5)在Java程序中使用System.loadLibrary()來加載這個動態連接庫文件。
    1.3

3、若是獲取共享變量的監視器鎖

  • 使用這個共享變量的時候,用synchronized關鍵字進行同步代碼塊
synchronized(共享變量){

}
  • 該共享變量在方法中的參數的時候
synchronzied void add (int a,int b){
	a + b;
}

4、虛假喚醒

  • 一個線程的共享變量經過調用自身的wait()方法來進入阻塞狀態,那若是想要從掛起狀態恢復到運行狀態,那麼只有三種方式:(1)其餘線程調用了該對象notify()或者notifyAll()方法的時候;(2)其餘線程調用了該對象的interrupt()方法;
  • 若是沒有以上兩種狀況,或者等待超時,仍然恢復運行狀態就叫虛假喚醒
  • 避免這種狀況的方式
synchronize(obj){
	while(條件不知足){
		obj.wait();
	}
}
  • 退出循環的條件就是知足了喚醒該線程的條件。

5、源碼:

相關文章
相關標籤/搜索