/** * @name Busy wait * @description Calling 'Thread.sleep' to control thread interaction is * less effective than waiting for a notification and may also * result in race conditions. Merely synchronizing over shared * variables in a loop to control thread interaction * may waste system resources and cause performance problems. * @kind problem * @problem.severity warning * @precision low * @id java/busy-wait * @tags reliability * correctness * concurrency */ import java class ReachFromStmt extends Stmt { ReachFromStmt() { exists(Method m | m.getBody() = this) or exists(WhileStmt w | w.getStmt() = this) } } class SleepMethod extends Method { SleepMethod() { this.getName() = "sleep" and this.getDeclaringType().hasQualifiedName("java.lang", "Thread") } } class SleepMethodAccess extends MethodAccess { SleepMethodAccess() { this.getMethod() instanceof SleepMethod } } class WaitMethod extends Method { WaitMethod() { this.getName() = "wait" and this.getDeclaringType() instanceof TypeObject } } class ConcurrentMethod extends Method { ConcurrentMethod() { this.getDeclaringType().getQualifiedName().matches("java.util.concurrent%") } } class CommunicationMethod extends Method { CommunicationMethod() { this instanceof WaitMethod or this instanceof ConcurrentMethod } } predicate callsCommunicationMethod(Method source) { source instanceof CommunicationMethod or exists(MethodAccess a, Method overridingMethod, Method target | callsCommunicationMethod(overridingMethod) and overridingMethod.overridesOrInstantiates*(target) and target = a.getMethod() and a.getEnclosingCallable() = source ) } class DangerStmt extends Stmt { DangerStmt() { exists(SleepMethodAccess sleep | sleep.getEnclosingStmt() = this) } } from WhileStmt s, DangerStmt d where d.getEnclosingStmt+() = s and not exists(MethodAccess call | callsCommunicationMethod(call.getMethod()) | call.getEnclosingStmt().getEnclosingStmt*() = s ) select d, "Prefer wait/notify or java.util.concurrent to communicate between threads."