静态方法与线程安全
多线程中使用静态方法是否有线程安全问题要看在静态方法中是否使用了静态成员。
因为,在多线程中使用同一个静态方法时,每个线程使用各自的实例字段(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方法中存在静态的全局变量导致。这应该是不被允许的,是框架性问题,还在进一步核实之中。