groovy.transform.Synchronized Maven / Gradle / Ivy
/*
* Copyright 2008-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.transform;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method annotation to make a method call synchronized for concurrency handling
* with some useful baked-in conventions.
*
* {@code @Synchronized} is a safer variant of the synchronized
method modifier.
* The annotation can only be used on static and instance methods. It operates similarly to
* the synchronized
keyword, but it locks on different objects. When used with
* an instance method, the synchronized
keyword locks on this
, but the annotation
* locks on a (by default automatically generated) field named $lock
.
* If the field does not exist, it is created for you. If you annotate a static method,
* the annotation locks on a static field named $LOCK
instead.
*
* If you want, you can create these locks yourself.
* The $lock
and $LOCK
fields will not be generated if you create
* them yourself. You can also choose to lock on another field, by specifying its name as
* parameter to the {@code @Synchronized} annotation. In this usage variant, the lock field
* will not be created automatically, and you must explicitly create it yourself.
*
* Rationale: Locking on this
or your own class object can have unfortunate side-effects,
* as other code not under your control can lock on these objects as well, which can
* cause race conditions and other nasty threading-related bugs.
*
* Example usage:
*
* class SynchronizedExample {
* private final myLock = new Object()
*
* {@code @}Synchronized
* static void greet() {
* println "world"
* }
*
* {@code @}Synchronized
* int answerToEverything() {
* return 42
* }
*
* {@code @}Synchronized("myLock")
* void foo() {
* println "bar"
* }
* }
*
* which becomes:
*
* class SynchronizedExample {
* private static final $LOCK = new Object[0]
* private final $lock = new Object[0]
* private final myLock = new Object()
*
* static void greet() {
* synchronized($LOCK) {
* println "world"
* }
* }
*
* int answerToEverything() {
* synchronized($lock) {
* return 42
* }
* }
*
* void foo() {
* synchronized(myLock) {
* println "bar"
* }
* }
* }
*
*
* Credits: this annotation is inspired by the Project Lombok annotation of the
* same name. The functionality has been kept similar to ease the learning
* curve when swapping between these two tools.
*
* Details: If $lock
and/or $LOCK
are auto-generated, the fields are initialized
* with an empty Object[]
array, and not just a new Object()
as many snippets using
* this pattern tend to use. This is because a new Object
is NOT serializable, but
* a 0-size array is. Therefore, using {@code @Synchronized} will not prevent your
* object from being serialized.
*
* @author Paul King
* @since 1.7.3
*/
@java.lang.annotation.Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
@GroovyASTTransformationClass("org.codehaus.groovy.transform.SynchronizedASTTransformation")
public @interface Synchronized {
/**
* @return if a user specified lock object with the given name should be used
*/
String value () default "";
}