wait
, notify
and notifyAll
The thread should own the monitor of the instance to call wait
, notify
or notifyAll
before the call.
So, the call of these basic method should be always located inside synchronized
block.
A thread can wake up by unexpected or unpredictable reason, so the call of wait
and the logic to process after wake-up should be guarded by loop.
So, the typical code block for calling wait
is
... final Object obj = new Object; ... synchronized (obj) { while (And for) obj.wait(timeout); ... // Perform action appropriate to condition } ...
notifyAll
... final Object obj = new Object; ... synchronized (obj) { //Perform some action to release the hold condition obj.notifyAll(); ... } ...
Typical code pattern for Regex API
The simplest code pattern for when a regular expression is used just once is to use static Pattern.matches
method.
boolean b = Pattern.matches("a*b", "aaaaab");
When using a expression several times, it is better to use compiled pattern object considering performance.
Pattern p = Pattern.compile("a*b"); boolean b1 = p.matcher("aaaaab").matches(); boolean b2 = p.matcher("bbbbb").matches();
Lazy initialization of field
Lazy initialization of instance field using double-checked locking
Prior to JDK 1.5, double-checked locking is not safe with Java because the reordering of object publication and initialization can not be controlled. But as of JDK 1.5, volatile
is specified not to be reordered, so it become possible to use safely double-checked locking with volatile field.
A typical code would be like this :
public class Worker{ private volatile Resource resource = null; //creating resource is expensive private final Object lock = new Object(); public Resource getResource(){ Resource r = resource; if(r == null){ //first check synchronized(lock){ r = resource; if(r == null){ //second check resource = r = new Resource(); } } } return r; } ... }
In above sample code, note that the lock
object is define to be final
, because reference on non final field can change any time.[5]
Lazy initialization of static field using initialization on demand holder class
On behalf of the characteristics of class loading and static initialization, static field can be safely lazy initialized using holder class without locking.
JVM load classes in lazy way and JVM run static initilizers at class initilization time which is after class loading but before the class is used by any thread. So, the static holder class having static field like the below would be lazy initialized in safe way.
public class Worker{ private static class ResourceHolder{ public static Resource resource = new Resource(); } public static Resource getResource(){ return ResourceHolder.resource; } ... }
More readings
- Double-checked locking in Wikipedia
- The "Double-Checked Locking is Broken" Declaration
- Synchronization and the Java Memory Model by Doug Lea
- "Item 71 : Use lazy initialization judiciously" of Effective Java, 2nd Ed.
- How Synchronization works in Java ? by Javin Paul
More codes
CommonAnnotationBeanPostProcessor.findResourceMetadata
method of Spring framework
The following code from Spring framework uses double-checked locking for non-volatile field.
Is it safe ?
Assuming ConcurrentHashMap.put
method may not be so complicated to expose stale values to threads and the local codes inside second check block (inner if
clause checking metadata == null
) would not be reordered with ConcurrentHashMap.put
method execution, the below code could be almost safe ?
package org.springframework.context.annotation; public class CommonAnnotationBeanPostProcessor extends ...{ ... private transient final Map<Class<?>, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<Class<?>, InjectionMetadata>(); ... private InjectionMetadata findResourceMetadata(final Class clazz) { // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(clazz); if (metadata == null) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(clazz); if (metadata == null) { final InjectionMetadata newMetadata = new InjectionMetadata(clazz); ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { public void doWith(Field field) { if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields"); } newMetadata.addInjectedField(new WebServiceRefElement(field, null)); } else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@EJB annotation is not supported on static fields"); } newMetadata.addInjectedField(new EjbRefElement(field, null)); } else if (field.isAnnotationPresent(Resource.class)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@Resource annotation is not supported on static fields"); } if (!ignoredResourceTypes.contains(field.getType().getName())) { newMetadata.addInjectedField(new ResourceElement(field, null)); } } } }); ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { public void doWith(Method method) { if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods"); } if (method.getParameterTypes().length != 1) { throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method); } PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); newMetadata.addInjectedMethod(new WebServiceRefElement(method, pd)); } else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@EJB annotation is not supported on static methods"); } if (method.getParameterTypes().length != 1) { throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method); } PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); newMetadata.addInjectedMethod(new EjbRefElement(method, pd)); } else if (method.isAnnotationPresent(Resource.class) && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@Resource annotation is not supported on static methods"); } Class[] paramTypes = method.getParameterTypes(); if (paramTypes.length != 1) { throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method); } if (!ignoredResourceTypes.contains(paramTypes[0].getName())) { PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); newMetadata.addInjectedMethod(new ResourceElement(method, pd)); } } } }); metadata = newMetadata; this.injectionMetadataCache.put(clazz, metadata); } } } return metadata; } ... }
1 comments:
Visit http://efectivejava.blogspot.in/ and know how lazy initialization affect the performance.
How lazy can we afford to be???
Post a Comment