FindBugs 规则整理:Multithreaded Correctness
DL_SYNCHRONIZATION_ON_BOOLEAN
Synchronization on Boolean could lead to deadlock
该代码同步一个封装的原始常量,例如一个Boolean类型private static Boolean inited = Boolean.FALSE;
...
synchronized(inited) {
if (!inited) {
init();
inited = Boolean.TRUE;
}
}
...
由于通常只存在两个布尔对象,此代码可能是同步的其他无关的代码中相同的对象,这时会导致反应迟钝和可能死锁
DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE
Synchronization on boxed primitive could lead to deadlock
该代码同步一个封装的原始常量,例如一个Integer类型。private static Integer count = 0;
...
synchronized(count) {
count++;
}
...
由于Integer对象可以共享和保存,此代码可能是同步的其他无关的代码中相同的对象,这时会导致反应迟钝和可能死锁
DL_SYNCHRONIZATION_ON_SHARED_CONSTANT
Synchronization on interned String could lead to deadlock
同步String类型的常量时,由于它被JVM中多个其他的对象所共有,这样在其他代码中会引起死锁。
DL_SYNCHRONIZATION_ON_UNSHARED_BOXED_PRIMITIVE
Synchronization on boxed primitive values
同步一个显然不是共有封装的原始值,例如一个Integer类型的对象。例如:private static final Integer fileLock = new Integer(1);
...
synchronized(fileLock) {
.. do something ..
}
...
它最后被定义为以下方式来代替:private static final Object fileLock = new Object();
DM_MONITOR_WAIT_ON_CONDITION
Monitor wait() called on Condition
方法中以java.util.concurrent.locks.Condition对象调用wait()。等待一个条件发生时应该使用在Condition接口中定义的await()方法。
DM_USELESS_THREAD
A thread was created using the default empty run method
这个方法没有通过run方法或者具体声明Thread类,也没有通过一个Runnable对象去定义一个线程,而这个线程出来浪费资源却什么也没有去做。
ESync_EMPTY_SYNC
Empty synchronized block
该代码包含一个空的同步块:synchronized() {}
IS2_INCONSISTENT_SYNC
Inconsistent synchronization
不合理的同步
IS_FIELD_NOT_GUARDED
Field not guarded against concurrent access
属性不能保证同步访问
JLM_JSR166_LOCK_MONITORENTER
Synchronization performed on Lock
实现java.util.concurrent.locks.Lock的对象调用了同步的方法。应该这样处理,对象被锁定/解锁时使用acquire()/ release()方法而不是使用同步的方法。
LI_LAZY_INIT_STATIC
Incorrect lazy initialization of static field
错误的对static属性进行了延迟初始化
LI_LAZY_INIT_UPDATE_STATIC
Incorrect lazy initialization and update of static field
这种方法包含一个不同步延迟初始化的静态字段。之后为字段赋值,对象存储到该位置后进一步更新或访问。字段后尽快让其他线程能够访问。如果该方法的进一步访问该字段为初始化对象提供服务,然后你有一个非常严重的多线程bug,除非别的东西阻止任何其他线程访问存储的对象,直到它完全初始化。
即使你有信心,该方法是永远不会被多个线程调用时,在它的值还没有被充分初始化或移动,不把它设定为static字段时它可能会更好。
ML_SYNC_ON_UPDATED_FIELD
Method synchronizes on an updated field
对象获取一个可变字段时进行同步。这是没有意义的,因为不同的线程可以在不同的对象同步。
MSF_MUTABLE_SERVLET_FIELD
Mutable servlet field
一个web服务一般只能创建一个servlet或者jsp的实例(例如:treates是一个单利类),它会被多个线程调用这个实例的方法服务于多个同时的请求。因此使用易变的字段属性产生竞争的情况。
MWN_MISMATCHED_NOTIFY
Mismatched notify()
此方法调用Object.notify()或Object.notifyAll()而没有获取到该对象的对象锁。调用notify()或notifyAll()而没有持有该对象的对象锁,将导致IllegalMonitorStateException异常。
MWN_MISMATCHED_WAIT
Mismatched wait()
此方法调用Object.wait()而没有获取到该对象的对象锁。调用wait()而没有持有该对象的对象锁,将导致IllegalMonitorStateException异常。
NP_SYNC_AND_NULL_CHECK_FIELD
Synchronize and null check on the same field.
如果代码块是同步的,那么久不可能为空。如果是空,同步时就会抛出NullPointerException异常。最好是在另一个代码块中进行同步。
NO_NOTIFY_NOT_NOTIFYALL
Using notify() rather than notifyAll()
调用 notify() 而不是 notifyAll() 方法。 Java的监控器通常用于多个条件。调用 notify() 只唤醒一个线程,这意味着该线程被唤醒只是满足的当前的唯一条件。
RS_READOBJECT_SYNC
Class’s readObject() method is synchronized
序列化类中定义了同步的readObject()。通过定义,反序列化创建的对象只有一个线程可以访问,因此没有必要的readObject()进行同步。如果的readObject()方法本身造成对象对另一个线程可见,那么这本身就是不好的编码方式。
RU_INVOKE_RUN
Invokes run on a thread (did you mean to start it instead?)
这种方法显式调用一个对象的 run()。一般来说,类是实现Runnable接口的,因为在一个新的线程他们将有自己的 run() 方法,在这种情况下 Thread.start() 方法调用是正确的。
SC_START_IN_CTOR
Constructor invokes Thread.start()
在构造函数中启动一个线程。如果类曾经被子类扩展过,那么这很可能是错的,因为线程将在子类构造之前开始启动。
SP_SPIN_ON_FIELD
Method spins on field
方法无限循环读取一个字段。编译器可合法悬挂宣读循环,变成一个无限循环的代码。这个类应该改变,所以使用适当的同步(包括等待和通知要求)
STCAL_INVOKE_ON_STATIC_CALENDAR_INSTANCE
Call to static Calendar
即使JavaDoc对此不包含暗示,而Calendars本身在多线程中使用就是不安全的。探测器发现当调用Calendars的实例时将会获得一个静态对象。
Calendar rightNow = Calendar.getInstance();
STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE
Call to static DateFormat
在官方的JavaDoc,DateFormats多线程使用本事就是不安全的。探测器发现调用一个DateFormat的实例将会获得一个静态对象。
myString = DateFormat.getDateInstance().format(myDate);
STCAL_STATIC_CALENDAR_INSTANCE
Static Calendar
Calendar在多线程中本身就是不安全的,如果在线程范围中共享一个Calendarde 实例而不使用一个同步的方法在应用中就会出现一些奇怪的行为。在sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate()中会抛出ArrayIndexOutOfBoundsExceptions or IndexOutOfBoundsExceptions异常。
STCAL_STATIC_SIMPLE_DATE_FORMAT_INSTANCE
Static DateFormat
DateFormat 在多线程中本身就是不安全的,如果在线程范围中共享一个DateFormat的实例而不使用一个同步的方法在应用中就会出现一些奇怪的行为。
SWL_SLEEP_WITH_LOCK_HELD
Method calls Thread.sleep() with a lock held
当持有对象时调用Thread.sleep()。这可能会导致很差的性能和可扩展性,或陷入死锁,因为其他线程可能正在等待获得锁。调用wait()是一个更好的主意,释放对象的持有以允许其他线程运行。
UG_SYNC_SET_UNSYNC_GET
Unsynchronized get method, synchronized set method
这个类包含类似命名的get和set方法。在set方法是同步方法和get方法是非同步方法。这可能会导致在运行时的不正确行为,因为调用的get方法不一定返回对象一致状态。 GET方法应该同步。
UL_UNRELEASED_LOCK
Method does not release lock on all paths
方法获得了当前的对象所,但是在方法中始终没有释放它。一个正确的示例如下:
Lock l = ...;
l.lock();
try {
// do something
} finally {
l.unlock();
}
UL_UNRELEASED_LOCK_EXCEPTION_PATH
方法获得了当前的对象所,但是在所有的异常处理中始终没有释放它。正确的示例同UL_UNRELEASED_LOCK
UW_UNCOND_WAIT
Unconditional wait
方法中包含调用java.lang.Object.wait(),而却没有放到条件流程控制中。该代码应确认条件尚未满足之前等待;先前任何通知将被忽略。
VO_VOLATILE_REFERENCE_TO_ARRAY
A volatile reference to an array doesn’t treat the array elements as volatile
声明一个变量引用数组,这可能不是你想要的。如果一个变量引用数组,那么对引用数组的读和写都是不安全的,但是数组元素不是变量。取得数组的变量值你可以使用java.util.concurrent包中的数组的原子性特性
WL_USING_GETCLASS_RATHER_THAN_CLASS_LITERAL
Sychronization on getClass rather than class literal
实例的方法中同步this.getClass(),如果这个类有子类集合,那么子类集合中的对象将会在这个类的各个子类上进行同步,这不是我们想要的效果,我们只要同步当前的类对象而不包含它的所有子类,可以同步类名.getClass()。例如,java.awt.Label的代码:
private static final String base = "label";
private static int nameCounter = 0;
String constructComponentName() {
synchronized (getClass()) {
return base + nameCounter++;
}
}
Label中的子类集合不可能在同一个子对象上进行同步,替换上面的方法为:
private static final String base = "label";
private static int nameCounter = 0;
String constructComponentName() {
synchronized (Label.class) {
return base + nameCounter++;
}
}
WS_WRITEOBJECT_SYNC
Class’s writeObject() method is synchronized but nothing else is
这个类有一个writeObject()方法是同步的,但是这个类中没有其他的同步方法。
WA_AWAIT_NOT_IN_LOOP
Condition.await() not in loop
方法没有在循环中调用java.util.concurrent.await()。如果对象是用于多种条件,打算调用wait()方法的条件可能不是实际发生的。
WA_NOT_IN_LOOP
Wait not in loop
这种方法包含调用java.lang.Object.wait(),而这并不是一个循环。如果监视器用于多个条件,打算调用wait()方法的条件可能不是实际发生的。
其他文章(持续更新)
FindBugs:简介与使用
FindBugs 规则整理:Bad Practice
FindBugs 规则整理:Style & Dodgy
FindBugs 规则整理:Internationalization
FindBugs 规则整理:Malicious Code Vulnerability
FindBugs 规则整理:Security & Experimental
FindBugs 规则整理:Performance
FindBugs 规则整理:CORRECTNESS
引用
整合以下文章过程中发现部分存在翻译错误,已做修正,同时感谢以下文章作者
FindBugs规则整理