Matt Raible has been building web applications for most of his adult life. He started tinkering with the web before Netscape 1.0 was even released. For the last 16 years, Matt has helped companies adopt open source technologies (Spring, Hibernate, Apache, Struts, Tapestry, Grails) and use them effectively. Matt has been a speaker at many conferences worldwide, including Devoxx, Jfokus, ÜberConf, No Fluff Just Stuff, and a host of others. Matt is a DZone MVB and is not an employee of DZone and has posted 149 posts at DZone. You can read more from them at their website. View Full User Profile

Concurrency on the JVM Using Scala with Venkat Subramaniam

09.10.2009
| 5980 views |
  • submit to reddit
This evening, I attended the Denver JUG where Venkat Subramaniam was speaking about Scala. Unfortunately, I arrived halfway through his Programming Scala talk and didn't get a chance to learn as much as I wanted to. What I did see made Scala look very powerful and (possibly) easier to learn than Java. Below are my notes from Venkat's talk.

Concurrency is important these days because we're in a world of multiple processors. When you have multiple threads running at one time, it can become painful. Before Java, you had to learn the API for multi-threading for each different platform. With Java's "Write once, debug everywhere", you only had to learn one API. Unfortunately, it's pretty low level: how to start a thread, manage it, stop it, etc. You also have to remember where to put synchronize in your code.

With Scala, immutability and its Actors make it easy to program concurrent systems. For example, here's a web service that retrieves stock prices in sequential order:

def getyearEndClosing(symbol : String, year : Int) = {
val url = "http://ichart.finance.yahoo.com/table.csv?s=" +
symbol + "&a=11&b=01&c" + year + "&d=11&e=31&f=" + year + "&g=m"
val data = io.Source.fromURL(url).mkString
val price = data.split("\n")(1).split(",")(4).toDouble
Thread.sleep(1000); // slow down internet
(symbol, price)
}

val symbols = List("APPL", "GOOG", "IBM", "JAVA", "MSFT")

val start = System.nanoTime

val top = (("", 0.0) /: symbols) { (topStock, symbol) =>
val (sym, price) = getYearEndClosing(symbol, 2008)

if (topStock._2 < price) (sym, price) else topStock
}

val end = System.nanoTime

println("Top stock is " + top._1 + " with price " + top._2)
println("Time taken " + (end - start)/10000000000.0)

To make this concurrent, we create Actors. Actors are nothing but Threads with a built-in message queue. Actors allow spawning separate threads to retrieve each stock price. Instead of doing: 

symbols.foreach { symbol => 
getYearEndClosing(symbol, 2008)
}

You can add actors:

val caller = self

symbols.foreach { symbol =>
actor { caller ! getYearEndClosing(symbol, 2008) }
}

Then remove val (sym, price) = getYearEndClosing(symbol, 2008) and replace it with: 

receive {
case(sym: String, price: Double) =>
if (topStock._2 < price) (sym, price) else topStock
}

After making this change, the time to execute the code dropped from ~7 seconds to ~2 seconds. Also, since nothing is mutable in this code, you don't have to worry about concurrency issues.

With Scala, you don't suffer the multiple-inheritance issues you do in Java. Instead you can use Traits to do mixins. For example:

import scala.actors._
import Actor._

class MyActor extends Actor {
def act() {
for(i <- 1 to 3) {
receive {
case msg => println("Got " + msg)
}
}
}

When extending Actor, you have to call MyActor.start to start the Actor. Writing actors this way is not recommended (not sure why, guessing because you have to manually start them).

Venkat is now showing an example that counts prime numbers and he's showing us how it pegs the CPU when counting how many exist between 1 and 1 million (78,499). After adding actor and receive logic, he shows how his Activity Monitor shows 185% CPU usage, indicating that both cores are being used.

What happens when one of the threads crashes and burns? The receive will wait forever. Because of this, using receive is a bad idea. It's much better to use receiveWithin(millis) to set a timeout. Then you can catch the timeout in the receiveWithin block using:

case TIMEOUT => println("Uh oh, timed out")

A more efficient way to use actors is using react instead of receive. With react, threads leave after putting the message on the queue and new threads are started to execute the block when the message is "reacted" to. One thing to remember with react is any code after the react block will never be executed. Just like receiveWithin(millis), you can use reactWithin(millis) to set a timeout.

The major thing I noticed between receive and react is Venkat often had to change the method logic to use react. To solve this, you can use loop (or better yet, loopWhile(condition)) to allow accessing the data outside the react block. In conclusion, reactWithin(millis) is best to use, unless you need to execute code after the react block.

Conclusion
This was a great talk by Venkat. He used TextMate the entire time to author and execute all his Scala examples. Better yet, he never used any sort of presentation. All he had was a "todo" list with topics (that he checked off as he progressed) and a sample.scala file.

Personally, I don't plan on using Scala in the near future, but that's mostly because I'm doing UI development and GWT and JavaScript are my favorite languages for that. On the server-side, I can see how it reduces the amount of Java you need to write (the compiler works for you instead of you working for the compiler). However, my impression is its sweet spot is when you need to easily author an efficient concurrent system.

If you're looking to learn Scala, I've heard Scala by Example (PDF) is a great getting-started resource. From there, I believe Programming in Scala and Venkat's Programming Scala are great books.

From http://raibledesigns.com/rd/entry/concurrency_on_the_jvm_using

Published at DZone with permission of Matt Raible, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Mike P(Okidoky) replied on Thu, 2009/09/10 - 2:47am

I highly doubt Scale will get anywhere, because it looks positively awful. It's unlikely anyone would find it "possibly" easier to learn than Java at all.

Armin Ehrenreich replied on Thu, 2009/09/10 - 3:22am in response to: Mike P(Okidoky)

You mean more awful than a doped Java with BGGA closures? I personally really don't think so.

oxbow_ lakes replied on Thu, 2009/09/10 - 4:15am

"With Scala, immutability and its Actors make it easy to program concurrent systems" -Let me get this straight, Matt: you have never used Scala and missed half of Venkat's talk, never written an Actor-based system and yet feel qualified to make statements like this based on some simple examples? And you feel that it's reasonable to write an article on a subject based on your in-depth knowledge of attending half a presentation? This is really quite ridiculous.

Matt Raible replied on Thu, 2009/09/10 - 8:37am in response to: oxbow_ lakes

There were two presentations, the first on Programming Scala and the 2nd on Concurrency on the JVM using Scala. I attended 45 minutes of the first one and all of the 2nd one. Most of the statements in this article were Venkat's, not mine. My thoughts are in the conclusion.

Have you written an Actor-based system? If so, what language did you use?

Steve Thompson replied on Thu, 2009/09/10 - 9:29am in response to: Mike P(Okidoky)

Yep, it is the most awful looking code in the world.  Consider this java -vs- this scala:

Java
class Person
{
String firstName, lastName;
Date dob;
public Person(String firstName, String lastName, Date dob) { ... }
// Getters and setters here ...
}
Scala
class Person(var firstName: String, var lastName: String, var dob: Date)

Isn't it obvious which is easier to read?  Only a sissy would go with a syntax like Scala's that didn't require so much manly boilerplate.  Just to give you a further sense of what I'm talking about here, let's pretend for a moment that we had a bunch of person objects, maybe in a list, and we'll call that 'people'.  Here again is how we might show an ordered list of such people by last name in Java -vs- Scala

 

Java
public static void showSorted(List people)
{
   Collections.sort(people, new Comparator()
   {
      @Override
      public int compare(Person arg0, Person arg1)
      {
         return arg0.getLastName().compareTo(arg1.getLastName());
      }
   });
   for(Person person : people)
     System.out.println(person);
}
Scala:
def showSorted(people: List[Person] =
    people sort (_.lastName < _.lastName) foreach println
Scala will obviously never get anywhere until it learns to look like it took LOADS OF EFFORT to achieve relatively LITTLE FUNCTIONALITY.  That is why I'm sticking with Java.

oxbow_ lakes replied on Thu, 2009/09/10 - 10:23am in response to: Matt Raible

Matt - I have written 3 production systems based around actors using Scala and it is anything but "easy" (although arguably worth it). Go to stackoverflow and have a look at some of the posts around scala and actors to understand some of the difficult choices an architect faces when writing an actor-based system. FWIW, Scala is an awesome language.

My point was that it does not enhance this site, Scala, nor your own reputation to be writing a fan-boy style post about a language that you clearly have no experience in. What are you bringing to the table? The article might as well have been written by Britney Spears: stick to writing about what you know.

Matt Raible replied on Thu, 2009/09/10 - 10:47am in response to: oxbow_ lakes

My point was that it does not enhance this site, Scala, nor your own reputation to be writing a fan-boy style post about a language that you clearly have no experience in.

FWIW, I didn't post this article here on Javalobby. I wrote it on my own blog and DZone's Editors posted it here on my behalf. I didn't ask them to.

What are you bringing to the table?

I'm merely telling folks what I learned at Venkat's talk. Doesn't seem like something that should cause so many harsh words.

Mike P(Okidoky) replied on Thu, 2009/09/10 - 6:34pm

FWIW, thanks to thompson4822's sarcastic post, I've started to take a closer look at Scala and I've come to cautiously appreciate it, although I can picture some people I worked with in the past not being able to wrap their heads around it.

Thank you Matt.

Eisen Hower replied on Thu, 2009/09/10 - 8:10pm

The only painful thing for Scala is lacking of good IDE support. I've tried Netbeans,Intellj and Eclipse. All of the plugins for Scala is far away from production. If there is no a good IDE, I think Scala will not be as popular as JAVA.

Bryan Taylor replied on Mon, 2009/09/14 - 5:21pm

I recently game my own talk on scala at the San Antonio JUG. Whether or not you use the actor model, I think scala solves a lot of problems that plauge java. Scala actually has stronger typing than java (it includes function types), yet is considerably more consise and elegant. Features like type inference, traits, case classes, pattern matching, closures, first class functions, higher order function, and actors all make solving problems in scala cleaner and eaiser than in Java.

Scala gets nearly all of the benefits in conciseness that ruby or groovy bring, but without the many costs associated with giving up static typing (speed, static code analysis, unit test inventory). James Strachan's blog on scala seems to have been a bellweather event, and I do not discount for a second that scala can and will start to gain traction. It's momentum is undeniable. I just hope that it doesn't get a bunch of fanboys the way that ruby did.

One last comment to the haters above... I've personally attended several useful talks by Matt and I respect his opinion. I see absolutely no reason to bash him for stating that he went to a talk and found something interesting. This idea that you have to be an expert to write an article on something is preposterous: just don't make false pretenses. Matt didn't.

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.