@[TOC]目录
Internationalization
1.DM_CONVERT_CASE
危险等级:关注
建议解决优先级:低
Consider using Locale parameterized version of invoked method
规则说明:考虑使用调用方法的语言环境参数化版本
A String is being converted to upper or lowercase, using the platform’s default encoding. This may result in improper conversions when used with international characters. Use the
String.toUpperCase( Locale l )
String.toLowerCase( Locale l )
versions instead.
产生原因:正在使用平台的默认编码将字符串转换为大写或小写。当与国际字符一起使用时,这可能会导致不适当的转换。使用
String.toUpperCase( Locale l )
String.toLowerCase( Locale l )
版本。
解决建议及实例**:)**
错误代码:
public String transCase() {
String title = "我是谁??think in eatting..";
title = title.toUpperCase();
return title;
}
改正代码:
public String transCase() {
String title = "我是谁??think in eatting..";
Locale local = new Locale("zh", "CN");
// local = Locale.getDefault();获取默认的Locale
title = title.toUpperCase(local);
return title;
}
2.DM_DEFAULT_ENCODING
危险等级:关注
建议解决优先级:高
Reliance on default encoding
规则说明:依赖默认编码
Found a call to a method which will perform a byte to String (or String to byte) conversion, and will assume that the default platform encoding is suitable. This will cause the application behaviour to vary between platforms. Use an alternative API and specify a charset name or Charset object explicitly.
产生原因:找到一个方法的调用,该方法将执行字节到字符串(或字符串到字节)的转换,并假定默认的平台编码是合适的。这将导致应用程序行为在不同平台之间发生变化。使用替代API并显式指定字符集名称或字符集对象。
解决建议及实例**:)**
错误代码:
public void transWithoutEncoding() {
byte[] b = "你是谁?".getBytes();//findbugs报错
String question = new String(b);//findbugs报错System.out.println(question);
}
改正代码:
public void transEncoding() throws UnsupportedEncodingException {
byte[] b = "你是谁?".getBytes("UTF-8");//指定编码格式
String question = new String(b, "UTF-8");
System.out.println(question);
}
Malicious code vulnerability
3.EI_EXPOSE_REP
危险等级:关注
建议解决优先级:普通
May expose internal representation by returning reference to mutable object
规则说明:可以通过返回对可变对象的引用来公开内部表示
Returning a reference to a mutable object value stored in one of the object’s fields exposes the internal representation of the object. If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.
产生原因:返回对存储在某个对象字段中的可变对象值的引用,将公开该对象的内部表示。如果实例是由不受信任的代码访问的,并且对可变对象的未检查更改会损害安全性或其他重要属性,那么您需要做一些不同的事情。在许多情况下,返回对象的新副本是更好的方法。
错误代码:
public int[] getArray2(int[] mutableArray) {
return mutable;
}
改正代码:
public int[] getArray(int[] mutableArray) {
return mutable.clone();
}
4.EI_EXPOSE_REP2
危险等级:关注
建议解决优先级:普通
May expose internal representation by incorporating reference to mutable object 规则说明:可以通过合并对可变对象的引用来公开内部表示
This code stores a reference to an externally mutable object into the internal representation of the object. If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Storing a copy of the object is better approach in many situations.
产生原因:该代码将对外部可变对象的引用存储到该对象的内部表示中。如果实例是由不受信任的代码访问的,并且对可变对象的未检查更改会损害安全性或其他重要属性,那么您需要做一些不同的事情。在许多情况下,存储对象的副本是更好的方法。
错误代码:
private int[] mutable = { 1 };
public void setMutable(int[] mutable) {
this.mutable = mutable;
}
改正代码:
private int[] mutable = { 1 };
public void setMutable(int[] mutable) {
this.mutable = mutable.clone();
}
5.FI_PUBLIC_SHOULD_BE_PROTECTED
危险等级:关注
建议解决优先级:普通
Finalizer should be protected, not public
规则说明:Finalizer 应该是proteced,而不是public
A class’s finalize() method should have protected access, not public.
产生原因:类的finalize()方法应该具有受保护的访问权,而不是公共访问权。
错误代码:
public void finalize() throws Throwable {
super.finalize();
System.out .println("finalize()方法:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,"
+ "若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,"
+ "由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,"
+ "GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。");
}
改正代码:
protected void finalize() throws Throwable {
super.finalize();
System.out .println("finalize()方法:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法," + "若未覆 盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入 F-Queue队列," + "由一低优先级线程执行该队列中对象的finalize方法。 执行finalize方法完毕后," + "GC会再次判断该对象是否可达,若不可达, 则进行回收,否则,对象“复活”。");
}
6.EI_EXPOSE_STATIC_REP2
危险等级:关注
建议解决优先级:普通
May expose internal static state by storing a mutable object into a static field
规则说明:可以通过将可变对象存储到静态字段来公开内部静态状态
This code stores a reference to an externally mutable object into a static field. If unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Storing a copy of the object is better approach in many situations.
产生原因:该代码将对外部可变对象的引用存储到静态字段中。如果未选中对可变对象的更改会危及安全性或其他重要属性,则需要做一些不同的事情。在许多情况下,存储对象的副本是更好的方法。
错误代码:
private static int[] mutable = { 1 };
public static void setMutable(int[] mutable) {
MultiThread.mutable = mutable;
}
改正代码:
private static int[] mutable = { 1 };
public static void setMutable(int[] mutable) {
MultiThread.mutable = mutable.clone();
}
7.MS_EXPOSE_REP
危险等级:关注
建议解决优先级:普通
Public static method may expose internal representation by returning array
规则说明:公共静态方法可以通过返回数组来公开内部表示
A public static method returns a reference to an array that is part of the static state of the class. Any code that calls this method can freely modify the underlying array. One fix is to return a copy of the array.
产生原因:公共静态方法返回对数组的引用,该数组是类的静态状态的一部分。任何调用此方法的代码都可以自由地修改底层数组。一个修复是返回数组的副本。
错误代码:
private static int[] array = { 1, 2, 3 };
public static int[] getArray() {
return array;
}
改正代码:
private static int[] array = { 1, 2, 3 };
public static int[] getArray() {
return array.clone();
}
15.MS_PKGPROTECT
危险等级:关注
建议解决优先级:普通
Field should be package protected
规则说明:字段应该被包保护
A mutable static field could be changed by malicious code or by accident. The field could be made package protected to avoid this vulnerability.
产生原因:可变静态字段可能被恶意代码或意外更改。可以将该字段设置为包保护,以避免此漏洞。
修饰符为protected是能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。要修改成包保护,就是同一个包可以访问。因此,修改为默认类型,即不加任何访问修饰符该模式下,只允许在同一个包中进行访问。
错误代码:
protected static int[] mutable = { 1 };//数组可变对象mutable
改正代码:
static int[] mutable = { 1 };//同一个包可以进行访问
Multithreaded correctness
2.DC_DOUBLECHECK
建议解决优先级:普通
Possible double check of field
规则说明:字段可能的双重检查
This method may contain an instance of double-checked locking. This idiom is not correct according to the semantics of the Java memory model. For more information, see the web page http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.
产生原因:此方法可能包含双重检查锁定的实例。根据Java内存模型的语义,这个习惯用法不正确。有关更多信息,请参阅web页面http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
错误代码:
// 单线程版本[没有问题] class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
helper = new Helper();
return helper;
} // other functions and members...
}
// 多线程版本 --很多东西可能会出错
class Foo2 {
private Helper helper = null;
public synchronized Helper getHelper() {
if (helper == null)
helper = new Helper();
return helper;
} // other functions and members...
}
// 多线程版本--双重检查锁定习惯用法,在优化编译器或共享内存多处理器的存在下不起作用。
class Foo3 {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) // findbugs报错
synchronized (this) {// 同步
if (helper == null)
helper = new Helper();
}
return helper;
} // other functions and members...
}
改正代码:
// JDK5或者更高版本[拓展了volatile]
class Foo5 {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized (this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
4.DL_SYNCHRONIZATION_ON_BOOLEAN
危险等级:关心
建议解决优先级:普通
Synchronization on Boolean
规则说明:布尔上的同步
The code synchronizes on a boxed primitive constant, such as an Boolean.
private static Boolean inited = Boolean.FALSE;
…
synchronized(inited) {
if (!inited) {
init();
inited = Boolean.TRUE;
}
}
…
Since there normally exist only two Boolean objects, this code could be synchronizing on the same object as other, unrelated code, leading to unresponsiveness and possible deadlock
See CERT CON08-J. Do not synchronize on objects that may be reused for more information.
产生原因:代码在一个被装箱的原语常量(如布尔值)上进行同步。
private static Boolean inited = Boolean.FALSE;
…
synchronized(inited) {
if (!inited) {
init();
inited = Boolean.TRUE;
}
}
…
由于通常只存在两个布尔对象,因此此代码可能与其他不相关的代码在同一个对象上同步,从而导致无响应性和可能的死锁
看到CERT CON08-J。不要同步可能被重用以获取更多信息的对象。
错误代码:
private static Boolean inited2 = Boolean.FALSE;
public void synchBoolean2() {
synchronized (inited2) {
if (!inited2) {
// init();
inited2 = Boolean.TRUE;
}
}
}
改正代码:
private AtomicBoolean inited = new AtomicBoolean(false);
public void synchBoolean() {
if (!inited.get()) {
// init();
inited.getAndSet(true);
}
}
5.DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE
危险等级:令人不安的
建议解决优先级:普通
Synchronization on boxed primitive
规则说明:对装箱原语的同步
The code synchronizes on a boxed primitive constant, such as an Integer.
private static Integer count = 0;
…
synchronized(count) {
count++;
}
…
Since Integer objects can be cached and shared, this code could be synchronizing on the same object as other, unrelated code, leading to unresponsiveness and possible deadlock
See CERT CON08-J. Do not synchronize on objects that may be reused for more information.
产生原因:代码在一个装箱的原语常量(如整数)上进行同步。
private static Integer count = 0;
…
synchronized(count) {
count++;
}
…
由于可以缓存和共享整数对象,因此此代码可能与其他不相关的代码在同一对象上同步,从而导致无响应性和可能的死锁
看到CERT CON08-J。不要同步可能被重用以获取更多信息的对象。
装箱原语的值在常量池中,可能被其他代码使用.修改成使用原子的AtomicInteger[自身带锁],或者用volatile和int加上锁
错误代码:
private Integer count = 0;
public void synchBoxed() {
synchronized (count) {
while (count < 5) {
// ...
count++;
}
}
}
改正代码:
private AtomicInteger countNum = new AtomicInteger(0);
public void synchBoxed2() {
while (countNum.get() < 5) {
// ...
countNum.getAndIncrement();
}
}
6.DL_SYNCHRONIZATION_ON_SHARED_CONSTANT
危险等级:令人不安的
建议解决优先级:普通
Synchronization on interned String
规则说明:在线字符串上的同步
The code synchronizes on interned String.
private static String LOCK = “LOCK”;
…
synchronized(LOCK) { …}
…
Constant Strings are interned and shared across all other classes loaded by the JVM. Thus, this could is locking on something that other code might also be locking. This could result in very strange and hard to diagnose blocking and deadlock behavior. See http://www.javalobby.org/java/forums/t96352.html and http://jira.codehaus.org/browse/JETTY-352.
See CERT CON08-J. Do not synchronize on objects that may be reused for more information.
产生原因:代码在被占用的字符串上同步。
private static String LOCK = “LOCK”;
…
synchronized(LOCK) { …}
…
常量字符串在JVM加载的所有其他类之间相互连接和共享。因此,这可能锁定了其他代码也可能锁定的东西。这可能导致非常奇怪和难以诊断阻塞和死锁行为。参见http://www.javalobby.org/java/forums/t96352.html和http://jira.codehaus.org/browse/JETTY-352。
看到CERT CON08-J。不要同步可能被重用以获取更多信息的对象
错误代码:
private static String name = "Java";
public void synchString() {
synchronized (name) {
// ... // name
}
}
改正代码:
private AtomicReference<String> strAtomic = new AtomicReference<String>( "Java");
public void synchString2() {
// strAtomic.set("C++");
}
9.DM_USELESS_THREAD
危险等级:关心
建议解决优先级:低
A thread was created using the default empty run method
规则说明:使用默认的空的run()方法创建一个线程
This method creates a thread without specifying a run method either by deriving from the Thread class, or by passing a Runnable object. This thread, then, does nothing but waste time.
产生原因:这个方法创建了一个线程,而不需要指定一个run方法,可以从thread类派生,也可以传递一个Runnable对象。那么,这个线程只会浪费时间。
创建了一个线程,但是没有重写run()方法,run()方法是线程执行的内容,没有重写,这个线程没有作用,浪费时间,考虑是否删除。
错误代码:
public void createThread() {
Thread thread1 = new Thread();
thread1.start();
}
10.ESync_EMPTY_SYNC
危险等级:令人不安的
建议解决优先级:普通
Empty synchronized block
规则说明:空同步块
The code contains an empty synchronized block:
synchronized() {}
Empty synchronized blocks are far more subtle and hard to use correctly than most people recognize, and empty synchronized blocks are almost never a better solution than less contrived solutions.
产生原因:代码包含一个空的同步块:
synchronized(){ }
空的同步块比大多数人认识到的要微妙得多,也很难正确地使用,而且空的同步块几乎从来都不是比不那么做作的解决方案更好的解决方案。
以下代码,add()方法里面有一个空的同步代码块,代码块没有做任何事情,考虑是否删除。
错误代码:
private volatile Roobot roobot = new Roobot();
public void add() {
synchronized (roobot) { }
}
13.JLM_JSR166_LOCK_MONITORENTER
危险等级:可怕
建议解决优先级:普通
Synchronization performed on Lock
规则说明:在锁上执行同步
This method performs synchronization an object that implements java.util.concurrent.locks.Lock. Such an object is locked/unlocked using acquire()/release() rather than using the synchronized (…) construct.
产生原因:这个方法执行一个实现java.util. concurrent.lock.lock的对象的同步。这样的对象是使用acquire()/release()实现锁定/解锁的,而不是使用synchronized(…)构造。
错误代码:
以下代码,在方法getRoobotName()使用了同步锁synchronized,但是Roobot实现了Lock接口,可以自己实现加锁解锁。
public class MyTestThread {
private volatile Roobot roobot = new Roobot();
public String getRoobotName() {
synchronized (roobot) {
return roobot.getName();
}
}
}
class Roobot implements Lock { //实现了Lock
private String name = "sanhao";
public void lock() { }
public void lockInterruptibly() throws InterruptedException { } public Condition newCondition() { return null; }
public boolean tryLock() { return false; }
public boolean tryLock(long arg0, TimeUnit arg1) throws InterruptedException { return false; }
public void unlock() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
改正代码:
public String getRoobotName() {
roobot.lock();
try {
return roobot.getName();
} finally {
roobot.unlock();
}
}
16.LI_LAZY_INIT_STATIC
危险等级:令人不安的
建议解决优先级:普通
Incorrect lazy initialization of static field
规则说明:静态字段的延迟初始化错误
This method contains an unsynchronized lazy initialization of a non-volatile static field. Because the compiler or processor may reorder instructions, threads are not guaranteed to see a completely initialized object, if the method can be called by multiple threads. You can make the field volatile to correct the problem. For more information, see the Java Memory Model web site.
产生原因:此方法包含非易失性静态字段的非同步延迟初始化。因为编译器或处理器可能重新排序指令,线程不能保证看到一个完全初始化的对象,如果该方法可以由多个线程调用。您可以使字段变得不稳定以纠正问题。有关更多信息,请参阅Java内存模型web站点。
错误代码:
以下代码,roobot是全局的变量,且通过延迟初始化,但是可能多个线程使用这个类,如果一个线程已经初始化了roobot的值,而另一个进行没有看到从而进行初始化,那么可能会出错。
private static Roobot roobot;
public Roobot getRoobot() {
if (roobot == null)
roobot = new Roobot();
return roobot;
}
改正代码:
给roobot加上volidate关键字,使其变得可见。一个线程初始化后,其他的线程可以立刻看见。
private volatile static Roobot roobot; //volatile可见
17.LI_LAZY_INIT_UPDATE_STATIC
危险等级:可怕的
建议解决优先级:高
ncorrect lazy initialization and update of static field
规则说明:静态字段的延迟初始化和更新错误
This method contains an unsynchronized lazy initialization of a static field. After the field is set, the object stored into that location is further updated or accessed. The setting of the field is visible to other threads as soon as it is set. If the futher accesses in the method that set the field serve to initialize the object, then you have a very serious multithreading bug, unless something else prevents any other thread from accessing the stored object until it is fully initialized.
Even if you feel confident that the method is never called by multiple threads, it might be better to not set the static field until the value you are setting it to is fully populated/initialized.
产生原因:此方法包含静态字段的非同步延迟初始化。设置字段后,存储在该位置的对象将被进一步更新或访问。该字段的设置一旦被设置,其他线程就可以看到。
如果进一步访问设置字段的方法用于初始化对象,那么就会出现一个非常严重的多线程错误,除非有其他原因阻止任何其他线程访问存储的对象,直到它被完全初始化。
即使您确信这个方法从来没有被多个线程调用过,在您将静态字段设置为完全填充/初始化值之前,最好不要设置静态字段。
错误代码:
private volatile static Roobot roobot;
// private static Roobot roobot;
public Roobot getRoobot() {
if (roobot == null) {
roobot = new Roobot();
roobot.setName("ldid");
}
return roobot;
}
改正代码:
private volatile static Roobot roobot;
// private static Roobot roobot;
public Roobot getRoobot() {
if (roobot == null) {
Roobot rbt = new Roobot();
rbt.setName("ldid");
roobot = rbt;
}
return roobot;
}
18.ML_SYNC_ON_FIELD_TO_GUARD_CHANGING_THAT_FIELD
危险等级:可怕的
建议解决优先级:高
Synchronization on field in futile attempt to guard that field
规则说明:字段上的同步,试图保护该字段
This method synchronizes on a field in what appears to be an attempt to guard against simultaneous updates to that field. But guarding a field gets a lock on the referenced object, not on the field. This may not provide the mutual exclusion you need, and other threads might be obtaining locks on the referenced objects (for other purposes). An example of this pattern would be:
private Long myNtfSeqNbrCounter = new Long(0);
private Long getNotificationSequenceNumber() {
Long result = null;
synchronized(myNtfSeqNbrCounter) {
result = new Long(myNtfSeqNbrCounter.longValue() + 1);
myNtfSeqNbrCounter = new Long(result.longValue());
}
return result;
}
产生原因:此方法在一个字段上同步,似乎是为了防止对该字段同时进行更新。但是,保护字段会在引用的对象上获得锁,而不是在字段上。这可能无法提供所需的互斥,其他线程可能正在获取引用对象上的锁(出于其他目的)。这种模式的一个例子是:
private Long myNtfSeqNbrCounter = new Long(0);
private Long getNotificationSequenceNumber() {
Long result = null;
synchronized(myNtfSeqNbrCounter) {
result = new Long(myNtfSeqNbrCounter.longValue() + 1);
myNtfSeqNbrCounter = new Long(result.longValue());
}
return result;
}
错误代码:
以下代码,synchronized 原本的意图是给变量myNtfSeqNbrCounter 进行同步,防止多个线程对它进行修改。但是实际上,synchronized 同步的是对象Long.valueOf(0),synchronized 是对象锁。
private Long myNtfSeqNbrCounter = Long.valueOf(0);
public Long getNotificationSequenceNumber() {
Long result = null;
synchronized (myNtfSeqNbrCounter) {
result = Long.valueOf(myNtfSeqNbrCounter.longValue() + 1);
myNtfSeqNbrCounter = result;// findbugs报错
}
return result;
}
改正代码:
因此,如果想要保护变量myNtfSeqNbrCounter 不被多个线程同时修改,对修改的方法进行加锁;或者:考虑使用原子变量。
private Long myNtfSeqNbrCounter = Long.valueOf(0);
public synchronized Long getNotificationSequenceNumber() {
Long result = null;
result = Long.valueOf(myNtfSeqNbrCounter.longValue() + 1);
myNtfSeqNbrCounter = result;
return result;
}
16.ML_SYNC_ON_UPDATED_FIELD
危险等级:令人不安的
建议解决优先级:普通
Method synchronizes on an updated field
规则说明:方法在更新的字段上同步
This method synchronizes on an object referenced from a mutable field. This is unlikely to have useful semantics, since different threads may be synchronizing on different objects.
产生原因:此方法对从可变字段引用的对象进行同步。这不太可能有有用的语义,因为不同的线程可能在不同的对象上同步。
错误代码:
以下代码,synchronizes 是变量锁,number是可变的(mutable),number=str使得number的引用发生改变,多个线程采用执行这个方法的时候,会在不同的对象上执行锁。
private volatile String number = "11";
public void testUpdateField(String str) {
number = str;//或: number = "0023";
synchronized (number) {
System.out.println(number);
}
}
改正代码:
因此,【这个解决方法自己也存在疑惑】
public void testUpdateField_new(String str) {
number = str;
lock.lock();
try {
System.out.println(number);
} finally {
lock.unlock();
}
}
25.NO_NOTIFY_NOT_NOTIFYALL
危险等级:关注
建议解决优先级:低
Using notify() rather than notifyAll()
规则说明:使用notify()而不是notifyAll()
This method calls notify() rather than notifyAll(). Java monitors are often used for multiple conditions. Calling notify() only wakes up one thread, meaning that the thread woken up might not be the one waiting for the condition that the caller just satisfied.
产生原因:这个方法调用notify()而不是notifyAll()。Java监视器经常用于多种情况。调用notify()只唤醒一个线程,这意味着被唤醒的线程可能不是等待调用者刚刚满足的条件的线程。
错误代码:
public static void main(String[] args) {
final MyTestThread test = new MyTestThread();
Thread thread2 = new Thread() {
public void run() {
test.notify();
}
};
thread2.start();
}
改正代码:
public static void main(String[] args) {
final MyTestThread test = new MyTestThread();
Thread thread2 = new Thread() {
public void run() {
test.notifyAll();
}
};
thread2.start();
}
28.RU_INVOKE_RUN
建议解决优先级:普通
Invokes run on a thread (did you mean to start it instead?)
规则说明:一个线程调用run()方法(你是否要用start()方法代替它?)
This method explicitly invokes run() on an object. In general, classes implement the Runnable interface because they are going to have their run() method invoked in a new thread, in which case Thread.start() is the right method to call.
产生原因:此方法显式调用对象上的run()。通常,类实现Runnable接口是因为它们将在一个新线程中调用它们的run()方法,在这种情况下,thread .start()是正确的调用方法。
错误代码:
以下代码,myThread1将在主线程中执行run()方法,这样没有达到线程的目的。是否要替换成start(),达到线程的目的。
public void testInvokeRun() {
MyThread myThread1 = new MyThread("thread:fw-1");
myThread1.run();
}
改正代码:
如果要达到线程的目的,修改成start(),将在线程中调用run()
public void testInvokeRun_new() {
MyThread myThread1 = new MyThread("thread:fw-1");
myThread1.start();
}
29.SC_START_IN_CTOR
危险等级:关注
建议解决优先级:低
Constructor invokes Thread.start()
规则说明:构造函数调用Thread.start()
The constructor starts a thread. This is likely to be wrong if the class is ever extended/subclassed, since the thread will be started before the subclass constructor is started.
产生原因:构造函数启动一个线程。如果类被扩展/子类化,这可能是错误的,因为线程将在子类构造函数启动之前启动。
错误代码:
以下代码,roobot是全局的变量,且通过延
private Thread thread1;
public MyTestThread() {
setThread1(new Thread() {
public void run() {
super.run();
}
});
thread1.start();
}
改正代码:
可以另外创建一个方法,在初始化之后调用该方法启动线程
private Thread thread1;
public MyTestThread() {
setThread1(new Thread() {
public void run() { super.run(); }
});
}
public void startThread() { //初始化实体后调用启动线程
thread1.start();
}
31.STCAL_INVOKE_ON_STATIC_CALENDAR_INSTANCE
危险等级:可怕的
建议解决优先级:普通
Call to static Calendar
规则说明:调用静态日历
Even though the JavaDoc does not contain a hint about it, Calendars are inherently unsafe for multihtreaded use. The detector has found a call to an instance of Calendar that has been obtained via a static field. This looks suspicous.
For more information on this see Sun Bug #6231579 and Sun Bug #6178997.
产生原因:即使JavaDoc不包含关于它的提示,对于多html的使用,日历本质上是不安全的。检测器发现通过静态字段获得的对Calendar实例的调用。这看起来suspicous。
有关这方面的更多信息,请参见Sun Bug #6231579和Sun Bug #6178997。
错误代码:
static Calendar calendar = new GregorianCalendar();
public void invokeCalendar() { //或static
calendar.add(1, 1);
}
改正代码:
Calendar calendar = new GregorianCalendar();
public void invokeCalendar() {
calendar.add(1, 1);
}
32.STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE
危险等级:可怕的
建议解决优先级:普通
Call to static DateFormat
规则说明:调用静态日期格式
As the JavaDoc states, DateFormats are inherently unsafe for multithreaded use. The detector has found a call to an instance of DateFormat that has been obtained via a static field. This looks suspicous.
For more information on this see Sun Bug #6231579 and Sun Bug #6178997.
产生原因:正如JavaDoc所述,日期格式对于多线程使用来说本质上是不安全的。检测器找到了对DateFormat实例的调用,该实例是通过静态字段获得的。这看起来奇怪。
有关这方面的更多信息,请参见Sun Bug #6231579和Sun Bug #6178997。
错误代码
static java.text.SimpleDateFormat tf = new java.text.SimpleDateFormat( "HH-mm-ss");
public static String formatTime(long t) {
return tf.format(new Date(t));
}
改正代码:
java.text.SimpleDateFormat tf = new java.text.SimpleDateFormat( "HH-mm-ss");
public String formatTime(long t) {
return tf.format(new Date(t));
}
35.SWL_SLEEP_WITH_LOCK_HELD
危险等级:可怕的
建议解决优先级:普通
Method calls Thread.sleep() with a lock held
规则说明:方法调用持有锁的Thread.sleep()
This method calls Thread.sleep() with a lock held. This may result in very poor performance and scalability, or a deadlock, since other threads may be waiting to acquire the lock. It is a much better idea to call wait() on the lock, which releases the lock and allows other threads to run.
产生原因:该方法调用持有锁的Thread.sleep()。这可能会导致非常糟糕的性能和可伸缩性,或者死锁,因为其他线程可能正在等待获得锁。在锁上调用wait()是一个更好的主意,它释放锁并允许其他线程运行。
错误代码:
sleep不释放对象锁,可能死锁或者性能问题,wait释放锁进入等待池
private Object object = new Object();
private int count = 0;
public void invoke() throws InterruptedException {
synchronized (object) {
while (count < 10) {
Thread.sleep(1000);
count++;
}
}
}
改正代码:
改成使用wait
private Object object = new Object();
private int count = 0;
public void invoke() throws InterruptedException {
synchronized (object) {
while (count < 10) {
object.wait(1000);
count++;
}
}
}
38.UL_UNRELEASED_LOCK
危险等级:令人不安的
建议解决优先级:高
Method does not release lock on all paths
规则说明:方法不会释放所有路径上的锁
This method acquires a JSR-166 (java.util.concurrent) lock, but does not release it on all paths out of the method. In general, the correct idiom for using a JSR-166 lock is:
Lock l = …;
l.lock();
try {
// do something
} finally {
l.unlock();
}
产生原因:该方法获得JSR-166 (java.util.concurrent)锁,但不会在方法的所有路径上释放锁。通常,使用JSR-166锁的正确习惯用法是:
Lock l = …;
l.lock();
try {
// do something
} finally {
l.unlock();
}
错误代码:
Lock lock = new ReentrantLock();
lock.lock();
if (flag) {
while (count < 10) {
newObject.wait(1000);
count++;
}
lock.unlock();
} else {
while (count < 10) {
newObject.wait(1000);
}
}
改正代码:
Lock lock = new ReentrantLock();
lock.lock();
try {
if (flag) {
while (count < 10) {
newObject.wait(1000);
count++;
}
} else {
while (count < 10) {
newObject.wait(1000);
}
}
} finally {
lock.unlock();
}
39.UL_UNRELEASED_LOCK_EXCEPTION_PATH
危险等级:令人不安的
建议解决优先级:普通
Method does not release lock on all exception paths
规则说明:方法不会释放所有异常路径上的锁
This method acquires a JSR-166 (java.util.concurrent) lock, but does not release it on all exception paths out of the method. In general, the correct idiom for using a JSR-166 lock is:
Lock l = ...;
l.lock();
try {
// do something
} finally {
l.unlock();
}
产生原因:该方法获得JSR-166 (java.util.concurrent)锁,但不会在方法之外的所有异常路径上释放锁。通常,使用JSR-166锁的正确习惯用法是:
Lock l = …;
l.lock();
try {
// do something
} finally {
l.unlock();
}
错误代码:
Lock lock = new ReentrantLock();
lock.lock();
try {
while (count < 10) {
newObject.wait(1000);
count++;
}
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
改正代码:
Lock lock = new ReentrantLock();
lock.lock();
try {
while (count < 10) {
newObject.wait(1000); count++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
41.VO_VOLATILE_INCREMENT
危险等级:令人不安的
建议解决优先级:普通
An increment to a volatile field isn’t atomic
规则说明:对volatile字段的增量不是原子的
This code increments a volatile field. Increments of volatile fields aren’t atomic. If more than one thread is incrementing the field at the same time, increments could be lost.
产生原因:这段代码增加了一个volatile字段。volatile字段的增量不是原子的。如果多个线程同时递增字段,增量可能会丢失。
错误代码:
如以下代码,变量inc虽然是用volatile关键字保证了可见性,但是inc++操作不是原子性的操作,而volatile不能保证原子性。所以,inc输出的结果可能和预期的不同。
public class FindBugs {
public volatile int inc = 0;
public void increase() {
inc++; //findbugs报错
}
public static void main(String[] args) {
final FindBugs test = new FindBugs();
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
for (int j = 0; j < 1000; j++) {
test.increase();
}
}
}.start();
}
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println(test.inc);
}
}
改正代码:
因此,想要保证inc的值的正确性,必须保证操作原子性,如:
1.添加关键字synchronized
public int inc = 0;//不用volatile,用了inc++还是会报错
public synchronized void increase() {
inc++;
}
2.采用Lock
public int inc = 0;
ReentrantLock lock = new ReentrantLock();
public void increase() {
lock.lock();
try {
inc++;
} finally{
lock.unlock();
}
}
3.采用AtomicInteger:java1.5以后
public AtomicInteger inc = new AtomicInteger(0);
public void increase() {
inc.getAndIncrement(); //自增
}
42.VO_VOLATILE_REFERENCE_TO_ARRAY
危险等级:令人不安的
建议解决优先级:普通
A volatile reference to an array doesn’t treat the array elements as volatile
规则说明:对数组的volatile引用不会将数组元素视为volatile
This declares a volatile reference to an array, which might not be what you want. With a volatile reference to an array, reads and writes of the reference to the array are treated as volatile, but the array elements are non-volatile. To get volatile array elements, you will need to use one of the atomic array classes in java.util.concurrent (provided in Java 5.0).
产生原因:这将声明对数组的volatile引用,这可能不是您想要的。对于数组的volatile引用,对数组的引用的读写被视为volatile,但是数组元素是非volatile的。要获取volatile数组元素,需要使用java.util中的原子数组类之一。并发(在Java 5.0中提供)。
错误代码:
如以下代码,对数组元素加锁,但其实可见性volatile不是在元素
private volatile String[] array = { "a", "b", "c", "d", "e" };
public void invoke() {
for (int i = 0; i < array.length; i++) {
synchronized (array[i]) {
array[i] = array[i] + "*";
System.out.println(array[i]);
}
}
}
改正代码:
修改成使用原子数组类
private String[] arr = { "a", "b", "c", "d", "e" };
private AtomicReferenceArray<String> atomicArray = new AtomicReferenceArray<>( arr);
public void invoke() {
for (int j = 0; j < atomicArray.length(); j++) {
synchronized (atomicArray.get(j)) {
atomicArray.set(j, atomicArray.get(j) + "*"); System.out.println(atomicArray.get(j));
}
}
}
43.WL_USING_GETCLASS_RATHER_THAN_CLASS_LITERAL
危险等级:关心
建议解决优先级:低
Synchronization on getClass rather than class literal
规则说明:同步getClass,而不是类的文字
This instance method synchronizes on this.getClass(). If this class is subclassed, subclasses will synchronize on the class object for the subclass, which isn’t likely what was intended. For example, consider this code from java.awt.Label:
private static final String base = “label”;
private static int nameCounter = 0;
String constructComponentName() {
synchronized (getClass()) {
return base + nameCounter++;
}
}
Subclasses of Label won’t synchronize on the same subclass, giving rise to a datarace. Instead, this code should be synchronizing on Label.class
private static final String base = "label";
private static int nameCounter = 0;
String constructComponentName() {
synchronized (Label.class) {
return base + nameCounter++;
}
}
Bug pattern contributed by Jason Mehrens
产生原因:这个实例方法在This . getclass()上同步。如果这个类是子类,子类将在子类的类对象上同步,这可能不是我们想要的。例如,考虑一下java.awt.Label中的代码:
private static final String base = “label”;
private static int nameCounter = 0;
String constructComponentName() {
synchronized (getClass()) {
return base + nameCounter++;
}
}
Subclasses of Label won’t synchronize on the same subclass, giving rise to a datarace. Instead, this code should be synchronizing on Label.class
private static final String base = "label";
private static int nameCounter = 0;
String constructComponentName() {
synchronized (Label.class) {
return base + nameCounter++;
}
}
Bug模式由Jason Mehrens提供
错误代码:
如以下代码,synchronized想要获得的是类锁,但是getClass()和.class是有区别的,getClass()是类的实例的方法,而.class是类的方法,当出现继承和多态的时候,getClass()和.class方法是不同。所以,使用getClass()和预期的可能不同
class SubFoo extends Foo {
public void invoke(String name) {
synchronized (getClass()) {
System.out.println(name + getClass().hashCode());
}
}
}
改正代码:
class SubFoo extends Foo {
public void invoke(String name) {
synchronized (SubFoo.class) {
System.err.println(name + SubFoo.class.hashCode());
}
}
}
44.WS_WRITEOBJECT_SYNC
危险等级:关心
建议解决优先级:低
Class’s writeObject() method is synchronized but nothing else is
规则说明:类的writeObject()方法是同步的,但没有其他方法是同步的
This class has a writeObject() method which is synchronized; however, no other method of the class is synchronized.
产生原因:该类有一个同步的writeObject()方法;但是,该类中没有其他方法是同步的。
错误代码:
class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private transient String fooName;
public Foo() {
fooName = "xixi";
}
private synchronized void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeBytes(fooName);
System.out.println("session 序列化");
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
ois.readByte();
fooName = "xixi";
System.out.println("session 反序列化");
}
}
改正代码:
private void writeObject(ObjectOutputStream oos) //去掉synchronized throws IOException {
oos.defaultWriteObject();
oos.writeBytes(fooName);
System.out.println("session 序列化");
}
46.WA_NOT_IN_LOOP
危险等级:关心
建议解决优先级:低
Wait not in loop
规则说明:wait()不在循环中
This method contains a call to java.lang.Object.wait() which is not in a loop. If the monitor is used for multiple conditions, the condition the caller intended to wait for might not be the one that actually occurred.
产生原因:该方法包含对不在循环中的java.util.concurrent. wait()(或变体)的调用。如果对象用于多个条件,则调用方希望等待的条件可能不是实际发生的条件。
错误代码:
如以下代码,newObject执行wait,进入等待池,线程的锁会释放,可能被其他线程获取并修改isLocked的值,如果使用if语句,wait执行完毕后线程直接执行代码,不会重新判断是否符合条件,这样数据可能出现错误
public void invoke() {
synchronized (newObject) {
try {
if (isLocked) {
newObject.wait(1000);
isLocked = !isLocked;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
改正代码:
因此,改成用while,重新获取锁之后会先执行判断。【或:使用两个if】
public void invoke() {
synchronized (newObject) {
try {
while (isLocked) {
newObject.wait(1000);
isLocked = !isLocked;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}