New paradigms for concurrent programming: Actor Model

http://www.ibm.com/developerworks/java/library/j-scala02049.html

http://www.ibm.com/developerworks/java/library/j-scala04109.html

http://www.scala-lang.org/node/242

http://www.malhar.net/sriram/kilim/

http://code.google.com/p/jetlang/

http://actorsguildframework.org/

http://osl.cs.uiuc.edu/af/

http://code.google.com/p/actorom/

http://wiki.github.com/jboner/akka

http://gpars.codehaus.org/Actor

Message Passing Concurrency

http://c2.com/cgi/wiki?MessagePassingConcurrency

Actor Model

Main implementation is Actor Model pattern.

http://c2.com/cgi/wiki?ActorsModel

Used by Erlang, scala.

http://c2.com/cgi/wiki?TransactionalActorModel

Actor model
Event oriented, asynchronous, message passing.
Actor has mailbox.
No shared-state, no concurrency, no blocking.
Actors communicate by sending message (in scala can be sync or async). Good source: http://www.scala-lang.org/node/242

Actors in scala can be distributed
Based on http://c2.com/cgi/wiki?MessagePassingConcurrency

terracotta: http://jonasboner.com/2008/01/25/clustering-scala-actors-with-terracotta.html
coherence: http://martin.elwin.com/blog/2008/06/clustering-scala-actors-with-oracle-coherence/
gigaspaces?: http://forum.openspaces.org/message.jspa?messageID=11643

http://forum.openspaces.org/thread.jspa?messageID=10380&#10380

No distributed Actor implementation.
Moreover currently scala objects cannot be inserted in a space.

Actor patter using GigaSpaces API: http://www.kimchy.org/actor-model-and-data-grids/

Scheme?

http://c2.com/cgi/wiki?ActorsModel

Axum

http://www.infoq.com/news/2008/06/scala-vs-erlang

http://en.wikipedia.org/wiki/Actor_model

http://www.scala-lang.org/node/242

http://www.javaworld.com/javaworld/jw-02-2009/jw-02-actor-concurrency1.html

http://www.javaworld.com/javaworld/jw-03-2009/jw-03-actor-concurrency2.html

http://ruben.savanne.be/articles/concurrency-in-erlang-scala

http://yarivsblog.com/articles/2008/05/18/erlang-vs-scala/

http://lambda-the-ultimate.org/node/1615

http://www.infoq.com/news/2007/08/ruby-1-9-fibers

http://www.infoq.com/presentations/actors-scala-immutability-pollack

http://on-ruby.blogspot.com/2008/01/ruby-concurrency-with-actors.html

Actor in Java

http://functionaljava.org/

http://code.google.com/p/jetlang/

http://osl.cs.uiuc.edu/af/

http://actorsguildframework.org/

http://www.malhar.net/sriram/kilim/index.html

Performacen comparison

http://sujitpal.blogspot.com/2009/01/more-java-actor-frameworks-compared.html

New paradigms for concurrent programming: Transactional Memory

Java and other mainstreams programming languages rely on shared state concurrency for concurrent programming. Race conditions between different threads are prevented using synchronization structures.
Traditionally in Java synchronized blocks along with wait and notify methods are used but Java 5 introduces new easier concepts.

Still it is quite difficult to implement correctly those patterns and there is no way to prove the code is correct.

New paradigms are slowly introduced intending to simplify or replace locking constructions.
This article will focus on Transactional Memory.

Transactional Memory

Transactional memory is an alternative to lock based synchronization relying on shared states.
This is achieved by applying the concept of transaction and ACID properties to your programming structures. Key points here are Atomicity and Isolation. Concurrent executions effects are equivalent to individual serial executions.

The main idea is to wrap a block of code in a transaction which is committed at the end. Read/write memory accesses can be dealt differently (optimistic/pessimistic locking) depending on concurrency control algorithm. If a conflict is detected during the execution of the atomic block by a thread the whole operation is roll-backed and retried. Details on retries strategies are implementation specific.

Biggest advantage of this technology is simplicity. Programmer doesn’t have to care about how to implement safe concurrent access (dealing with locks, wait..) but only identify which block of code should be treated as atomic.
Better performances are not ensured but correctness is.

More detailed explanation on transactional memory can be found here, here, here and here.

Usage

In most of languages/libraries transactional memory support will be little intrusive by relying on special keyword or meta-data. For language without built-in transactional memory support this can be achieved by using bytecode manipulation.

Regular synchronized block


public void test() {
  synchronized(map1) {
    synchronized(map2) {
      value = map1.remove("key");
      map2.put("key", value+1);
    }
  }
}

Here you have to synchronize modification of 2 structures. This can be hard to correctly implement especially if several methods have to synchronize on the same structure. In this particular sample you have to take a particular care about potential deadlock which might be introduce if you don’t acquire/release locks in the same order.

Transactional memory


@Atomic
public void test() {
  value = map1.remove("key"); 
  map2.put("key", value+1);
}

Transactional memory ensures that your atomic block of code will be executed atomically. Still there is no magic and you need to identify atomic blocks of code.
Moreover you don’t have to think about locking optimization, which is hard especially when multiple structure access have to be synchronized from different execution path. Because everything is handled by the language (or library) smart optimization might be applied and you are not responsible for this.

This technique does not solve all concurrency problems but certainly helps for some of them. Still you will have to rely on Semaphore, Barrier and other advanced structures for more complex scenarii.

Language support

Haskell

Haskell was the first language to have builtin support for STM. Details can be found here.

Java

Atomic types, locks (Java 5) and Fork/Join (Java 7) are lock-free structures using compare and swap algorithm. Implementation is similar to transactional memory but for a single element. Details about their implementation choice can be found here and here.

To benefit from atomicity capacity you will have to use a full transactional memory implementation.

A number of Java implementation are available:

Multiverse’s author discusses similarities between TL2 and Multi Version Concurrency Control (MVCC) algorithms .

.Net

Microsoft also provides STM support with STM.NET.

Fortress

Fortress language supports transactional memory as part of its semantic. Current implementation relies on DTSM2 but plan is to switch to Hybrid Transactional Memory (mix of hardware and software implementation) when available.

On top of atomicity, most of fortress syntaxic structures (loop for instance) are executed in parallel by multiple threads. While powerful this introduces complexity as a simple loop adding numbers will have to manipulate atomic structures.

Clojure

Clojure supports STM based on MVCC.

Hardware Transaction Memory

In the near future transactional memory paradigm will be implemented at hardware level providing even better performance. Rock processor from SUN (recently released paper describes HTM features) and Vega 3 from Azul implement it. Other approaches have been documented here and here.

Cons

Transactional memory is not the panacea and some critics (here and here) appeared recently.
Others techniques aiming at facilitating concurrent programming will be discussed later.

Attach API and JMX export

Attach API is a powerful technology introduced in SUN JVM starting JDK6. It provides the ability to list local JVMs, get some information about them and dynamically deploy agent based on Instrument API (Java) or JVMTI (native code).

Those agents are becoming quite popular and can be used for profiling and dynamic bytecode manipulation. A growing number of products rely on one of those technologies: JProfiler, Yourkit, JRat, JavaRebel, OpenJPA, BTrace.

Even so you don’t plan to write your own native profiler or instrument classes by modifying bytecode there can be usage of Attach API. Local JVMs can be detected and manipulated without the need of any particular startup option. Most of the tools shipped with the JDK rely on this API (jconsole, jps, jps, jinfo, jstsat,..).

We will see in this article how to leverage this API to start remote JMX connector dynamically on a running JVM.

Platform MBeanServer

JMX technology provides a Java standard to monitor and manage a JVM. Starting Java 5 internals of the JVM are exposed using it in the platform MBeanServer. More details about how it works here.

To access an MBeanServer it must be exported through a connector, most of the time based on RMI. Several MBeanServer can be created in a single JVM but the platform one is always present and there are good chances that you only manipulated this one. More details about dealing with multiples MBeanServer can be found here.

By default the platform MBeanServer is not exported but setting com.sun.management.jmxremote Java property creates a local JMX connector which allows to browse the platform MBeanServer (only from the same machine with the same user).
Note that setting com.sun.management.jmxremote.local.only Java property to false allows to make this connector remotely available but this is to mimic an old behaviour and should not be considered a good practise.

Setting com.sun.management.jmxremote.port to some numerical value will export the platform MBeanServer to a JMX connector accessible from a remote machine.
Because this facility is implemented as a Java agent, tools like JConsole and visualvm can create dynamically this connector using the Attach API. The monitoring agent can be found under JDK_HOME/lib/management-agent.jar.

More information on JMX monitoring can be found here.


Dynamic export of Platform MBeanServer

Using the Attach API to export locally the platform MBeanServer is straight-forward:

final VirtualMachine virtualMachine = VirtualMachine.attach("PID");
final String home = virtualMachine.getSystemProperties().getProperty("java.home");
final String agent = home + File.separator + "lib" + File.separator + "management-agent.jar";
virtualMachine.loadAgent(agent);
virtualMachine.detach();

This can be extended to export it remotely:

final VirtualMachine virtualMachine = VirtualMachine.attach("PID");
final String home = virtualMachine.getSystemProperties().getProperty("java.home");
final String agent = home + File.separator + "lib" + File.separator + "management-agent.jar";
virtualMachine.loadAgent(agent, "com.sun.management.jmxremote.port=5000," +
"com.sun.management.jmxremote.authenticate=false,com.sun.management.jmxremote.ssl=false");
virtualMachine.detach();

Unfortunately this method does not allow to stop the deployed connector. This could be achieved by creating your own agent that would export the platform MBeanServer itself and listen to remote event to offer the unexport ability. Such an option is extensively covered here.

Attach API can be disabled on your JVM by setting -XX:+DisableAttachMechanism Java property. If com.sun.management.jmxremote Java property is not set then  external tool won’t be able to deploy the management agent remotely. This way you forbid access to the platform MBeanServer, even locally.

Extended jps

When the platform MBeanServer is exported with a local connector com.sun.management.jmxremote.localConnectorAddress Java property is set to the corresponding JMX URL value.
When remotely exported the JMX URL will follow the syntax service:jmx:rmi:///jndi/rmi://host:port/jmxrmi where host is the machine where the JVM runs and port is the value of com.sun.management.jmxremote.port Java property .

By using those 2 informations we can create an extended jps which will print local and remote JMX URL is available.

for (final VirtualMachineDescriptor descriptor : VirtualMachine.list()) {
  System.out.print(descriptor.id());  
  System.out.println(" "+descriptor.displayName().split(" ")[0]);
  final VirtualMachine virtualMachine = VirtualMachine.attach(descriptor.id());

  final String localConnectorAddress = virtualMachine.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
  if (localConnectorAddress != null) {
    System.out.println(localConnectorAddress!=null?"    local jmx ("+localConnectorAddress+")":"");
  }
  final String remoteConnectorPort = virtualMachine.getSystemProperties().getProperty("com.sun.management.jmxremote.port");
  if (remoteConnectorPort != null) {
    final String remoteConnectorAddress = "service:jmx:rmi:///jndi/rmi://"+InetAddress.getLocalHost().getHostName()+":"+remoteConnectorPort+"/jmxrmi";
    System.out.println(remoteConnectorAddress!=null?"    remote jmx ("+remoteConnectorAddress+")":"");
  }
  virtualMachine.detach();
}

Note that when dynamically exporting the platform MBeanServer remotely com.sun.management.jmxremote.port Java property will not be set thus we cannot rely on this code to infer the remote JMX service URL.

Unfortunately those techniques only allow to get information on the platform MBeanServer and not other MBeanServer. Even so you can list newly created MBeanServer there is no way to access connectors used to export them.