日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java安全编码指南之:Thread API调用规则

發布時間:2024/2/28 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java安全编码指南之:Thread API调用规则 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 簡介
  • start一個Thread
  • 不要使用ThreadGroup
  • 不要使用stop()方法
  • wait 和 await 需要放在循環中調用

簡介

java中多線程的開發中少不了使用Thread,我們在使用Thread中提供的API過程中,應該注意些什么規則呢?

一起來看一看吧。

start一個Thread

Thread中有兩個方法,一個是start方法,一個是run方法,兩個都可以調用,那么兩個有什么區別呢?

先看一下start方法:

public synchronized void start() {if (threadStatus != 0)throw new IllegalThreadStateException();group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}}private native void start0();

start()是一個synchronized的方法,通過它會去調用native的start0方法,而最終將會調用Thread的run()方法。

我們知道,創建一個Thread有兩種方式,一種是傳入一個Runnable,一個是繼承Thread,并重寫run()方法。

如果我們直接調用Thread的run()方法會發生什么事情呢?

先看一下run方法的定義:

public void run() {if (target != null) {target.run();}}

默認情況下, 這個target就是一個Runnable對象,如果Thread是通過Runnable來構建的話,調用Thread.run()會在當前線程中運行run方法中的內容。

如果Thread是以其形式構建,并且沒有重新run()方法,那么直接調用Thread.run()將什么都不會做。

public void wrongStart(){Runnable runnable= ()-> System.out.println("in thread running!");Thread thread= new Thread(runnable);thread.run();}public void correctStart(){Runnable runnable= ()-> System.out.println("in thread running!");Thread thread= new Thread(runnable);thread.start();}

所以,上面兩種調用方式,只有第二種是正確的。

不要使用ThreadGroup

Thread中有個字段類型是java.lang.ThreadGroup,這個主要是用來給Thread進行分組,我們看下Thread的這個構造函數:

public Thread(ThreadGroup group, Runnable target) {this(group, target, "Thread-" + nextThreadNum(), 0);}

上面的構造函數可以在傳入runnable的同時傳遞一個ThreadGroup對Thread進行分組。

如果沒有指定ThreadGroup,那么將會為其分配一個默認的default group。

ThreadGroup是做什么的呢?ThreadGroup是java 1.0引入的方法,主要是一次性的對一組thread進行操作。我們可以調用ThreadGroup.interrupt()來一次性的對整個Group的Thread進行interrupts操作。

雖然ThreadGroup提供了很多有用的方法,但是其中很多方法都被廢棄了,比如:allowThreadSuspension(), resume(), stop(), 和 suspend(),并且ThreadGroup中還有很多方法是非線程安全的:

  • ThreadGroup.activeCount()

這個方法主要是用來統計一個ThreadGroup中活動的線程個數,這個方法會統計還未啟動的線程,同時也會受系統線程的影響,所以是不準確的。

  • ThreadGroup.enumerate()

這個方法是將ThreadGroup和子group的線程拷貝到一個數組中,但是如果數組太小了,多余的線程是會被自動忽略的。

ThreadGroup本身有一個 stop() 方法用來停止所有的線程,但是stop是不安全的,已經被廢棄了。

那么我們該怎么去安全的停止很多個線程呢?

使用executor.shutdown()就可以了。

不要使用stop()方法

剛剛講了ThreadGroup中不要調用stop()方法,因為stop是不安全的。

調用stop方法會立馬釋放線程持有的所有的鎖,并且會拋出ThreadDeath異常。

因為會釋放所有的鎖,所以可能會造成受這些鎖保護的對象的狀態發生不一致的情況。

替代的方法有兩種,一種是使用volatile flag變量,來控制線程的循環執行:

private volatile boolean done = false;public void shutDown(){this.done= true;}public void stopWithFlag(){Runnable runnable= ()->{while(!done){System.out.println("in Runnable");}};Thread thread= new Thread(runnable);thread.start();shutDown();}

另外一種方法就是調用interrupt(), 這里我們要注意interrupt()的使用要點:

  • 如果當前線程實例在調用Object類的wait(),wait(long)或wait(long,int)方法或join(),join(long),join(long,int)方法,或者在該實例中調用了Thread.sleep(long)或Thread.sleep(long,int)方法,并且正在阻塞狀態中時,則其中斷狀態將被清除,并將收到InterruptedException。

  • 如果此線程在InterruptibleChannel上的I/O操作中處于被阻塞狀態,則該channel將被關閉,該線程的中斷狀態將被設置為true,并且該線程將收到java.nio.channels.ClosedByInterruptException異常。

  • 如果此線程在java.nio.channels.Selector中處于被被阻塞狀態,則將設置該線程的中斷狀態為true,并且它將立即從select操作中返回。

  • 如果上面的情況都不成立,則設置中斷狀態為true。

  • 先看下面的例子:

    public static void main(String[] args) {Runnable runnable= ()->{while (!Thread.interrupted()) {System.out.println("in thread");}};Thread thread= new Thread(runnable);thread.start();Thread.sleep(5000);thread.interrupt();}

    我們在while循環中調用了Thread.interrupted()方法用來判斷線程是否被設置了中斷位,然后在main方法中調用了thread.interrupt()來設置中斷,最終可以正確的停止Thread。

    注意,這里運行的Thread并沒有被阻塞,所以并不滿足我們上面提到的第一個條件。

    下面我們再看一個例子:

    public static void main(String[] args) {Runnable runnable= ()->{while (!Thread.interrupted()) {System.out.println("in thread");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}};Thread thread= new Thread(runnable);thread.start();thread.interrupt();}

    這個例子和上面的例子不同之處就是在于,Thread中調用了sleep方法,導致Thread被阻塞了,最終滿足了第一個條件,從而不會設置終端位,只會拋出InterruptedException,所以這個例子中線程是不會被停止的,大家一定要注意。

    wait 和 await 需要放在循環中調用

    為什么要放在循環中呢?因為我們希望wait不是被錯誤的被喚醒,所以我們需要在wait被喚醒之后,重新檢測一遍條件。

    錯誤的調用是放在if語句中:

    synchronized (object) {if (<condition does not hold>) {object.wait();}// Proceed when condition holds }

    正確的方法是放在while循環中:

    synchronized (object) {while (<condition does not hold>) {object.wait();}// Proceed when condition holds }

    本文的代碼:

    learn-java-base-9-to-20/tree/master/security

    本文已收錄于 http://www.flydean.com/java-security-code-line-thread/

    最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

    歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!

    總結

    以上是生活随笔為你收集整理的java安全编码指南之:Thread API调用规则的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。