java 函式式介面 Functional Interface
阿新 • • 發佈:2021-07-30
執行緒的概念
程序是系統進行資源分配和排程的基本單位,執行緒則是程序的一個執行路徑,一個程序中至少有一個執行緒,程序中的多個執行緒共享程序的資源。真正佔用 CPU 的是執行緒,執行緒是 CPU 分配的基本單位。
Java 經常以 Main 函式作為程式執行的入口,Main 函式所在的執行緒就是程序中的一個執行緒,一般稱為主執行緒。在 Java 中多個執行緒共享程序的堆和方法區,但是每個執行緒有自己的程式計數器和棧。
執行緒建立的方式
繼承 Thread 方式
publicclassThreadStudyextendsThread{
@Override
publicvoidrun(){
System.out.println(Thread.currentThread.getName());
}
}
//啟動方式
ThreadthreadStudy=newThreadStudy();
threadStudy.start();實現 Runnable 介面方式
publicclassRunnableTaskStudyimplementsRunnable{
@Override
publicvoidrun(){
System.out.println(Thread.currentTread.getName());
}
}
//啟動方式
RunnableTaskStudytaskStudy=newRunnableTaskStudy();
Threadthread1=newThread(taskStudy);
Threadthread2=new
thread1.start();
thread2.start();實現 Callable 介面,該方式可以獲取返回值
publicclassCallableTaskStudyimplementsCallable<String>{
@Override
publicvoidcall()throwsException{
return"hello";
}
}
//啟動
FutureTask<String>futureTask=newFutureTask<>(newCallableStudy());
Threadthread=newThread(futureTask);
thread.start();
try
Stringresult=futureTask.get();
LOGGER.info("Resultis"+result);
}catch(InterruptedException|ExecutionExceptione){
LOGGER.info(e.getMessage());
throwe;
}
執行緒通知與等待
當一個執行緒呼叫一個共享變數的 wait() 方法後,該執行緒被阻塞掛起,直到下面幾件事情發生返回:
其它執行緒呼叫了該共享變數的 notify(), notifyAll() 方法。 其它執行緒呼叫了該執行緒的 interrupt() 方法,該執行緒丟擲 InterruptedException 異常後返回。
呼叫共享變數的 wait() 方法前,必須先獲取該共享變數的監視器鎖。
一個執行緒呼叫了共享變數的 notify() 方法時後,會喚醒一個在該共享變數上呼叫 wait() 系列方法後被掛起的執行緒
被喚醒的執行緒不能馬上從 wait() 方法返回並繼續執行,它必須在獲取了共享變數的監視器鎖之後才可以返回。
程式碼實現
程式碼實現需要注意的地方是在判斷是否滿足執行條件時需要使用 while 迴圈來防止虛假喚醒
staticclassPurchaseThreadextendsThread{
privatestaticfinalLoggerLOGGER=Logger.getLogger(PurchaseThread.class.toString());
privatefinalResourceresource;
publicPurchaseThread(Resourceresource){
this.resource=resource;
}
@Override
publicvoidrun(){
try{
resource.purchase();
}catch(InterruptedExceptionexp){
LOGGER.severe(exp.getMessage());
}
}
}
staticclassSaleThreadextendsThread{
privatestaticfinalLoggerLOGGER=Logger.getLogger(SaleThread.class.toString());
privatefinalResourceresource;
publicSaleThread(Resourceresource){
this.resource=resource;
}
@Override
publicvoidrun(){
try{
resource.sale();
}catch(InterruptedExceptionexp){
LOGGER.severe(exp.getMessage());
}
}
}
staticclassResource{
privatestaticfinalLoggerLOGGER=Logger.getLogger(Resource.class.toString());
privatestaticfinalintMAX_SIZE=10;
privatefinalDeque<String>products;
publicResource(Deque<String>products){
this.products=products;
}
publicvoidpurchase()throwsInterruptedException{
synchronized(products){
while(products.size()==MAX_SIZE){
products.wait();
}
while(products.size()<MAX_SIZE){
products.addLast(UUID.randomUUID().toString());
}
products.notifyAll();
}
}
publicvoidsale()throwsInterruptedException{
synchronized(products){
//這裡需要通過while迴圈來防止虛假喚醒,如果這裡使用if作為判斷,當執行緒醒來之後就直接執行後面的邏輯了
while(products.size()==0){
products.wait();
}
LOGGER.info(products.removeLast());
products.notifyAll();
}
}
}
執行緒中斷
interrupt() 方法
A 執行緒可以呼叫 B 執行緒的 interrupt() 方法來將 B 執行緒的中斷標誌位設定為 true 並返回,這裡並不會影響 B 執行緒的執行。如果 B 呼叫了 wait() 系列函式,join() 方法,sleep() 方法而被掛起,這個時候 A 呼叫 B 執行緒的 interrupt() 方法,執行緒 B 會在呼叫方法出丟擲 InterruptedException 異常並返回。
isInterrupted()
檢測當前執行緒是否被中斷
interrupted()
檢測當前執行緒被中斷,如果當前執行緒被中斷,則清除中斷標誌位。
程式碼實現
staticclassPrintThreadextendsThread{
privatestaticfinalLoggerLOGGER=Logger.getLogger(PrintThread.class.toString());
@Override
publicvoidrun(){
while(!Thread.currentThread().isInterrupted()){
LOGGER.info("PrintYes");
try{
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedExceptionexp){
//當休眠時被中斷會丟擲中斷異常
LOGGER.severe(exp.getMessage());
break;
}
}
}
}
PrintThreadthread=newPrintThread();
thread.start();
TimeUnit.SECONDS.sleep(1);
//這裡中斷執行緒
thread.interrupt();
LOGGER.info("Mainthreadisover.");