Findbugs缺陷規則及案例(國際化問題&惡意的代碼漏洞&多線程問題)

@[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(); 
} 
} 
} 

我是帥哥

什麼是帥哥

我是大帥哥

帥哥的定義

我比你帥

孤獨寂寞冷
人生真是寂寥如雪
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章