CodeQL 文档

对装箱类型或字符串进行同步

ID: java/sync-on-boxed-types
Kind: problem
Security severity: 
Severity: error
Precision: very-high
Tags:
   - reliability
   - correctness
   - concurrency
   - language-features
   - external/cwe/cwe-662
Query suites:
   - java-security-and-quality.qls

单击以查看 CodeQL 代码库中的查询

代码不应该对装箱类型(例如 IntegerBoolean)或类型 String 的变量或字段进行同步,因为它很可能包含在整个程序中使用的对象。例如,Boolean.TRUE 持有一个将在整个程序中的许多地方使用的单个实例:每当 true 被自动装箱或 Boolean.valueOf 使用 true 作为参数被调用时,都会返回 Boolean 的相同实例。因此,两个类对类型为 Boolean 的字段进行同步很可能最终对同一个对象进行同步。这可能导致死锁或线程被不必要地阻塞。

建议

对特定锁对象进行同步,而不是使用具有装箱类型的对象。

示例

在以下示例中,目的是让 ThreadAThreadB 同时运行。不幸的是,ThreadA.lockThreadB.lock 都引用了同一个对象(即 String "lock" 的内部值),因此它们运行方法中的同步块无法并发执行。

class BadSynchronize{
		
	class ThreadA extends Thread{
		private String value = "lock"
		
		public void run(){
			synchronized(value){
				//...
			}
		}
	}
	
	class ThreadB extends Thread{
		private String value = "lock"
		
		public void run(){
			synchronized(value){
				//...
			}
		}
	}
	
	public void run(){
		new ThreadA().start();
		new ThreadB().start();
	}
		
}

在以下示例中,展示了上面推荐的方法。为每个线程创建了一个单独的锁对象,允许它们并发执行。

class GoodSynchronize{
		
	class ThreadA extends Thread{
		private Object lock = new Object();
		
		public void run(){
			synchronized(lock){
				//...
			}
		}
	}
	
	class ThreadB extends Thread{
		private Object lock = new Object();
				
		public void run(){
			synchronized(lock){
				//...
			}
		}
	}
	
	public void run(){
		new ThreadA().start();
		new ThreadB().start();
	}
		
}

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私