2003年,Herb Sutter在他的“免费午餐结束了”一文中揭露了业界最大的“肮脏小秘密”,清楚地表明,越来越快的处理器时代已经结束,将由一个新的并行化时代取代。单个芯片上的“核心”(虚拟CPU)。 这个消息在编程界引起了震惊,因为正确地保持线程安全的代码一直都存在,从理论上讲,即使不是在实践中,高能力的软件开发人员也对您的公司而言过于昂贵。 似乎很少有特权的人对Java的线程模型和并发API以及“ synchronized”关键字足够了解,可以编写既提供安全性又提供吞吐量的代码……而且大多数人都很难理解。
据推测,该行业的其余部分只能自力更生,这显然不是可取的结论,至少对于要开发该软件的IT部门而言,这是不可行的。
与.NET空间中Scala的姊妹语言F#一样,Scala也是所谓的“并发问题”解决方案之一。 在本专栏中,我介绍了Scala的多个属性,这些属性使它更适合编写线程安全代码,例如默认情况下为不可变对象,以及用于返回对象副本而不修改其内容的设计偏好。 不过,Scala对并发的支持远不止于此。 现在是时候开始在Scala库中四处看看,看看那里生活着什么。
并发基础
在深入了解Scala的并发支持之前,最好先确保您对Java的基本并发模型有充分的了解,因为Scala对并发的支持在某种程度上建立在Java提供的特性和功能之上。 JVM和支持库。 为此,清单1中的代码包含一个基本的并发问题,称为生产者/消费者问题(如Sun Java Tutorial的“ Guarded Blocks”部分所述)。 请注意,Java Tutorial版本在其解决方案中未使用java.util.concurrent
类,而是更喜欢使用java.lang.Object
的旧wait()
/ notifyAll()
方法:
清单1.生产者/消费者(Java5之前的版本)
package com.tedneward.scalaexamples.notj5;
class Producer implements Runnable
{
private Drop drop;
private String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
public Producer(Drop drop) { this.drop = drop; }
public void run()
{
for (int i = 0; i < importantInfo.length; i++)
{
drop.put(importantInfo[i]);
}
drop.put("DONE");
}
}
class Consumer implements Runnable
{
private Drop drop;
public Consumer(Drop drop) { this.drop = drop; }
public void run()
{
for (String message = drop.take(); !message.equals("DONE");
message = drop.take())
{
System.out.format("MESSAGE RECEIVED: %s%n", message);
}
}
}
class Drop
{
//Message sent from producer to consumer.
private String message;
//True if consumer should wait for producer to send message,
//false if producer should wait for consumer to retrieve message.
private boolean empty = true;
//Object to use to synchronize against so as to not "leak" the
//"this" monitor
private Object lock = new Object();
public String take()
{
synchronized(lock)
{
//Wait until message is available.
while (empty)
{
try
{
lock.wait();
}
catch (InterruptedException e) {}
}
//Toggle status.
empty = true;
//Notify producer that status has changed.
lock.notifyAll();
return message;
}
}
public void put(String message)
{
synchronized(lock)
{
//Wait until message has been retrieved.
while (!empty)
{
try
{
lock.wait();
} catch (InterruptedException e) {}
}
//Toggle status.
empty = false;
//Store message.
this.message = message;
//Notify consumer that status has changed.
lock.notifyAll();
}
}
}
public class ProdConSample
{
public static void main(String[] args)
{