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规则整理


版权声明

![Creative Commons BY-NC-ND 4.0 International License](/images/cc.png)

Lam’s Blog by Binghe Lin is licensed under a Creative Commons BY-NC-ND 4.0 International License.
林炳河创作并维护的Lam’s Blog采用创作共用保留署名-非商业-禁止演绎4.0国际许可证

本文首发于Lam’s Blog - Knowledeg as Action,版权所有,侵权必究。

本文永久链接:http://linbinghe.com/2017/baebe2db.html