首頁  >  文章  >  Java  >  Java多線程run方法中怎麼直接呼叫service業務類

Java多線程run方法中怎麼直接呼叫service業務類

王林
王林轉載
2023-05-12 14:22:062470瀏覽

多執行緒run方法中直接呼叫service業務類別應注意

Java多執行緒run方法裡邊使用service業務類別會產生java.lang.NullPointerException異常的問題,這是由於spring注入的業務類為null,或直接new的業務物件也為null。

多執行緒為了執行緒安全性會防止注入,因此在想使用service業務類別時,需要使用ApplicationContext的方式來取得bean的方法來取得service類別。

取得ApplicationContext的類別要實作ApplicationContextAware接口,如下:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
public class ApplicationContextUtil implements ApplicationContextAware {
 
	private static ApplicationContext context;
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		this.context = context;
	}
	public static ApplicationContext getContext() {
		return context;
	}
}

然後在run方法使用上述方法建立業務對象,如下:

XXXServiceI xxxService = ApplicationContextUtil.getContext.getBean(XXXServiceI.class);

這樣就能正常使用該業務類了。

圖解如下

Java多線程run方法中怎麼直接呼叫service業務類

Java多線程run方法中怎麼直接呼叫service業務類

Java多線程run方法中怎麼直接呼叫service業務類

#多執行緒知識點

執行緒啟動的四種方式

1.、繼承Thread類別重寫Thread的run方法,在run方法中進行操作,用start方法啟動執行緒

Java多線程run方法中怎麼直接呼叫service業務類

2、繼承Runnable接口,實作run方法,在run方法中進行操作,需要傳入目前類別的實例物件建立一個Thread實例,然後呼叫start方法啟動執行緒

Java多線程run方法中怎麼直接呼叫service業務類

3、實作Callable接口,重寫call()方法,需要注意的是,前兩種方法都是不需要回應的,直接就執行了,但是實現Callable接口,重寫call()方法則是需要等待線程回應的,所以雖然啟動了其他線程,但是卻是一個線程在執行,並不能算是標準的多線程。

Java多線程run方法中怎麼直接呼叫service業務類

4、執行緒池

Java多線程run方法中怎麼直接呼叫service業務類

#使用@Aysnc註解實作多執行緒

#同一個類中,方法A 引用方法B 方法B加異步@Async註解不會有效

被加@Async方法和呼叫方不能再同一個類別中

用戶執行緒與守護執行緒的區別

Java內創建的線程預設是創建用戶線程,例如new Thread(線程物件).start

    Thread thread = new Thread();
    // 默认为false,都是用户线程
    thread.setDaemon(true); // 表示设置为守护线程
    thread.setDaemon(false); // 表示设置为用户线程
  • 用戶線程:不zhi隨著其他執行緒的死亡而死亡,只有兩種情況dao死掉,一是在運行中出現異常而終止,二是正常把程式執行完畢,執行緒死亡

  • 守護線程:隨著用戶線程的死亡而死亡,當用戶線程死完了守護線程也死了,例如gc垃圾回收線程。用戶線程存在,那gc就有活著的必要,反之就沒用了。

線程的六種狀態

1. New:初始狀態,執行緒被創建,沒有呼叫start()

2. Runnable:運行狀態,Java執行緒把作業系統中的就緒和運行兩種狀態統一稱為「運行中」

3. Blocked:阻塞,執行緒進入等待狀態,執行緒因為某種原因,放棄了CPU的使用權

  • 阻塞的幾個情況:

  • #A. 等待阻塞:運行的執行緒執行了wait(),JVM會把目前執行緒放入等待佇列

  • B. 同步阻塞:執行的執行緒在取得物件的同步鎖定時,如果該同步鎖定被其他執行緒佔用了,JVM會把目前執行緒放入鎖池中

  • C. 其他阻塞:運行的執行緒執行sleep(),join()或發出IO請求時,JVM會把目前執行緒設定為阻塞狀態,當sleep()執行完,join()執行緒終止,IO處理完畢執行緒再次恢復

4. Waiting:等待狀態

5. timed_waiting:逾時等待狀態,逾時日後自動回傳

6. terminated:終止狀態,目前執行緒執行完畢

Java鎖定的可重入性

java鎖定的可重入性機制可以解決下面這個問題,直接上程式碼:

 public class Demo1 {
    public synchronized void functionA(){
        System.out.println("iAmFunctionA");
        functionB();
    }
    public synchronized void functionB(){
        System.out.println("iAmFunctionB");
    }

假設Java沒有提供synchronized 強制原子性的內部鎖定機制:functionA()和functionB()都是同步方法,當執行緒進入funcitonA()會取得該類別的物件鎖,這個鎖"new Demo1()",在functionA()對方法functionB()做了調用,但是functionB()也是同步的,因此該線程需要再次獲得該物件鎖(new Demo1()),但是JVM會認為這個執行緒已經取得了此物件的鎖,而不能再取得,從而無法呼叫functionB()方法,從而造成死鎖。

執行緒池的四個拒絕策略

當執行緒池的任務快取佇列已滿並且執行緒池中的執行緒數目達到maximumPoolSize時,如果還有任務到來就會採取任務拒絕策略,通常有以下四種策略:

ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException例外。

ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出例外。

ThreadPoolExecutor.DiscardOldestPolicy:丟棄佇列最前面的任務,然後重新提交被拒絕的任務

ThreadPoolExecutor.CallerRunsPolicy:由呼叫執行緒(提交任務的執行緒)處理該任務

sleep和wait的差異

  • #sleep是執行緒中的方法,但是wait是Object中的方法

  • sleep方法不會釋放lock,但是wait會釋放,而且會加入到等待佇列中

  • sleep不需要被喚醒,但wait需要

為什麼wait(),notify(),notifyAll()在物件中,而不在Thread類別中

java中鎖的層級是物件級而不是執行緒級,每個物件都有鎖,透過執行緒取得。如果wait()方法在執行緒中,則執行緒正在等待的是哪個鎖就不明顯了。

以上是Java多線程run方法中怎麼直接呼叫service業務類的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除