Ik ben op dit moment bezig om een blogpost te schrijven over visibility problems in Spring based applications.
Ik ben benieuwd wat jullie er van vinden en of jullie het begrijpen. En ik wil uiteraard ook vragen over de technische problemen erachter
Het stuk is trouwens nog lang niet klaar (kromme zinnen, stukken nog niet af, redenaties veel te kort etc), maar de kern van het verhaal staat er; alle belangrijke ingredienten zitten eirn.
++ Spring and visibility problems
todo: hoe zit het met de niet singleton beans?
Ik ben benieuwd wat jullie er van vinden en of jullie het begrijpen. En ik wil uiteraard ook vragen over de technische problemen erachter
Het stuk is trouwens nog lang niet klaar (kromme zinnen, stukken nog niet af, redenaties veel te kort etc), maar de kern van het verhaal staat er; alle belangrijke ingredienten zitten eirn.
++ Spring and visibility problems
Abstract
Spring is a great framework, but I expect that a lot of Spring based applications, could be subject to a specific concurrency problem: visibility [todo]. This blogentry describes the cause and effects of this problem, and also how it can be solved.Visibility problems
Most programmers don't have much experience with multi-threading, and most have a very simplistic view on reality: if a thread makes a change to a variable, this change directly is visible to all other threads. This view is called sequential consistency, but the problem is that no virtual machine supports it. The reason why sequential consistency is not supported, is that it greatly reduces performance. If every change of a variable should be visible to all threads, a lot of optimizations can't be used. To name a few:- caches for multi-core/multi-cpu systems, would be useless, because a stale value is not acceptable.
- registers can't be used to function as (a very fast) local copy of a variable, because a change to a register is not visible in other threads.
- make field volatile
- make field final
- use in synchronized context
Spring based applications and visibility problems
I expect that a lot of Spring based applications, are subject to visibility problems. A lot of beans are singletons: dao's, controllers, managers etc, and these singletons often are shared by many threads, eg:- threads from the servlet container
- threads from remoting middleware
- threads from jmx
public class EmployeeManagerImpl implements EmployeeManager{
private EmployeeDao employeeDao;
public setEmployeeDao(EmployeeDao employeeDao){
this.employeeDao = employeeDao;
}
public void fire(long employeeId){
Employee employee = employeeDao.load(employeeId);
employee.fire();
}
}
And the bean configuration that belongs to it:
The visibility problem here is that the reference to the employeeDao maybe not is visible in a thread that uses the employeeDao, and this could lead to a NullPointerException.
The problem can be solved in a few ways:
- Make all fields volatile. Although it sounds quite strange, because a value is not going to change after it has been set, a volatile field safely publishes the value. Personally I don't like this solution very much
- Make the fields final because it also safely publishes the value. The problem with final fields is that they only can be set by constructor injection and Spring promotes setter injection. Personally I never liked setter injection (although it prevents complex constructors) because it is hard to understand what can and can't change. Especially with more complex objects, you don't want to worry about changing fields and maintaining invariants.
Problem not that bad?
The visibility problems are not that bad under virtual machines that support JSR133 (like Java 5). This is because they support a mechanism called "Piggybacking on Synchronization" bad name, mention tim peierls: save handoff, save passing). Piggybacking on Synchronization uses the safe publication of a variable X, to safely publish all unsafely-published-variables that are changed before X. In this case the placement in the Map where the beans are stored, provides this memory barrier, and that is why beans, that have visibility problems themselfes, are safely published. org.springframework.beans.factory.support.DefaultSingletonBeanFactory
protected void addSingleton(String beanName, Object sharedBean) {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(sharedBean, "Singleton object must not be null");
synchronized (this.singletonCache) {
this.singletonCache.put(beanName, sharedBean);
}
}
The unlock of the monitor-lock of the singletonCache is the reason why piggybacking works (it is a happens-before rule, see JCiP): Todo: gebruik je die lock ook zo snel mogelijk weer als je iets uit de map wilt halen?
Personally I'm not too happy with this side effect because I don't know
Another problem is that it only works on virtual machines that support JSR133. On virtual machines that don't support JSR133, the memory model is undefined. So it is guessing if an application is threadsafe.todo: hoe zit het met de niet singleton beans?
[ Voor 7% gewijzigd door een moderator op 23-11-2006 14:42 ]