多線程中使用靜態方法是否有線程安全問題要看在靜態方法中是否使用了靜態成員。
因為,在多線程中使用同一個靜態方法時,每個線程使用各自的實例字段(instance field)的副本,而共享一個靜態字段(static field)。所以說,如果該靜態方法不去操作一個靜態成員,只在方法內部使用實例字段(instance field),不會引起安全性問題。但是,如果該靜態方法操作了一個靜態字段,則需要靜態方法中采用互斥訪問的方式進行安全處理。也就是說當某個靜態類的靜態方法使用了synchronized時實際上是對這個方法里的全局靜態變量進行線程互斥保護。
線程安全問題是因為“共享資源”被多個線程同時訪問時存在的問題,也就是說互斥方法synchronized是爭對域的,也就是說不管是靜態類還是非靜態類,只有多個線程可能訪問到同一塊內存區域時,才會存在線程安全問題。
當對靜態類方法使用synchronized時,整個類是線程互斥的。
在實際問題中,發現有一個不明顯的靜態類可能導致的線程安全問題。如下代碼片段:
public static Bitmap resizeBitmapByScale( Bitmap bitmap, float scale, boolean recycle) { int width = Math.round(bitmap.getWidth() * scale); int height = Math.round(bitmap.getHeight() * scale); if (width == 0 || height == 0) return bitmap; if (width == bitmap.getWidth() && height == bitmap.getHeight()) return bitmap; Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap)); Canvas canvas = new Canvas(target); canvas.scale(scale, scale); Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); canvas.drawBitmap(bitmap, 0, 0, paint); if (recycle) bitmap.recycle(); return target; }
沒有使用任何全局靜態變量,經檢查bitmap對象也是線程安全的。但是仍然出現了線程安全問題,在方法前面加上synchronized關鍵字后,解決了這個線程問題。但我們如何確定這個不明顯的線程安全問題到底是因為這個方法里的哪個“共享資源”引起的呢?可以采用Lock鎖的方式來確定共享資源的范圍
private static Object mLock = new Object(); synchronized(mLock){ canvas.drawBitmap(); }
如上,通過互斥全局變量mLock來保護某部分代碼段來縮小線程安全范圍。
目前懷疑是該方法的native方法中存在靜態的全局變量導致。這應該是不被允許的,是框架性問題,還在進一步核實之中。