Although artificial intelligence (as a set of technologies, not in the sense of mimicking human intelligence) is here since a long time in many forms and ways, it’s a term that quite some people, certainly IT vendors, don’t like to use that much anymore – but artificial intelligence is real, for your business too.
Instead of talking about artificial intelligence (AI) many describe the current wave of AI innovation and acceleration with – admittedly somewhat differently positioned – terms and concepts such as cognitive computing or focus on several real-life applications of artificial intelligence that often start with words such as “smart” (omni-present in anything Internet of Things as well), “intelligent”, “predictive” and, indeed, “cognitive”, depending on the exact application – and vendor. Despite the term issues, artificial intelligence is essential for and in, among others, information management, medicine/healthcare, data analysis, digital transformation, security (cybersecurity and others), various consumer applications, scientific advances, FinTech, predictive systems and so much more. An exploration.
The historical issue with artificial intelligence – is cognitive better?
There are many reasons why several vendors doubt using the term artificial intelligence for AI solutions/innovations and often package them in another term (trust us, we’ve been there). Artificial intelligence (AI) is a term that has somewhat of a negative connotation in general perception but also in the perception of technology leaders and firms.
One major issue is that artificial intelligence – which is really a broad concept/reality, covering many technologies and realities – has become like a thing we talk about and also seem to need to have an opinion/feeling about, with thanks to, among others, popular culture. Hollywood loves AI (or better: superintelligence, not the same). It makes for good sci-fi blockbusters and movies where non-human ‘things’ such as robots take over the world. The fact that AI is such a broad concept leads to misunderstandings about what it exactly means. Some people are really speaking about machine learning when they talk about AI. Others essentially talk about analytics and in doomsday movie scenarios everything gets mixed, including robotics and superintelligence, something we don’t have yet. And in most cases we really talk about some form of AI.
Fast growing AI technologies for consumer facing industries include chat bots and Virtual Personal Assistants (VPA) and smart advisors. Source
This phenomenon goes hand in hand with the fact that artificial intelligence has failed to deliver upon expectations from previous ‘popularity waves’ (going back to the previous Millennium, see box below this article) and is really old as a concept, research field and set of technologies – making it less appealing for many vendors, as obviously AI technologies and applications, as well as expectations, have evolved, albeit less than some like us to believe.
Still, deep learning, image recognition, hypothesis generation, artificial neural networks, they’re all real and parts are used in various applications. According to IDC, cognitive computing is one of six Innovation Accelerators on top of its third platform and the company expects global spending on cognitive systems to reach nearly $31.3 billion in 2019. You’ll notice IDC speaks about cognitive too (more about the meaning of cognitive systems as an innovation accelerator further in this article).
Artificial intelligence is being used faster in many technological and societal areas although there is quite some hype about what “it” can do from vendors. Still, the increasing attention and adoption of forms of AI in specific areas triggers debates about how far we want it to go in the future. Prominent technology leaders have warned about the danger and think tanks and associations have been set up to think about and watch over the long-term impact of AI (and robotics) with dicussions on the future of humanity and the impact of superintelligence but also, closer to today’s concerns, impact of automation/AI/robots on employment. Anyway, it again adds to that mix of ingredients that creates the conditions to strengthen the negative connotation regarding the term artificial intelligence – and as current political shifts show automation/digitalization as a whole.
If it makes us feel more comfortable to talk about “intelligent”, “cognitive” or “smart” anything, so be it. What matters more is how artificial intelligence is here and increasingly will be, why it’s here, how it helps and is used and what it can mean for you.
Artificial intelligence in context: how it interacts with other transformational technologies
When people try to explain that artificial intelligence is already here since a long time in some form, they often refer to the algorithms that power Google’s search technology. Or an avalanche of apps on mobile devices. Strictly speaking, these algorithms are not the same as AI though.
The artificial intelligence market is estimated to grow from USD 419.7 Million in 2014 to USD 5.05 Billion by 2020, at a CAGR of 53.65% from 2015 to 2020. Source
Also think about speech recognition, for instance. Or identification technologies, product recommendations and even the electronic games we play. And of course there are many examples, depending on industry or function. Marketing, for instance, uses a bunch of platforms with forms of AI: from the sentiment analysis in social platforms to the predictive capabilities in data-driven marketing solutions.
So, artificial intelligence is many things. A graphic from research by Narrative Science shows various areas in the broader ecosystem of AI, ranging from text mining to deep learning and recommendation engines. The latter is something everyone knows or at least uses with recommendation engines being literally everywhere. And then there are all those apps such as Uber, Airbnb and the likes that connect you with respectively an Uber driver in the neighbourhood and an Airbnb place to stay – powered by AI.
To understand the role and current wave of AI in today’s and tomorrow’s business and society context it’s important to look at the realities and technologies underneath the big overlapping umbrella term. It’s also important to see the current wave of artificial intelligence in a context of big data, unstructured data, integration and digital transformation.
One of the reasons why artificial intelligence – maybe not the term – has become so hot right now is the fact that it is a perfect fit for – and even indispensable enabler of – other technologies and the possibilities they offer. Sometimes you just need artificial intelligence techniques.
The interconnectedness of 3rd platform technologies and artificial intelligence
As we don’t feel the urge to reinvent the lists of technologies that enable and accelerate digital transformation and innovation, we’ll use IDC’s previously mentioned famous 3rd platform, although you can use many others.
Innovation accelerators – new core technologies as added by IDC to its 3rd Platform
The foundation of that so-called 3rd platform consists of 4 sets of technologies that are interconnected and de facto inherently connected with AI as well.
As a reminder: the high interconnectivity of technologies and processes in real-life applications is a core trait of what we’ve come to known as the digital transformation or DX economy.
Each of these sets of technologies (they are not things either but just as AI consist of several technologies and, more importantly, applications and consequences) are technological drivers of digital transformation as such.
On top of these 4 foundational sets or pillars (cloud, mobility, social and Big Data/Analytics) come so-called innovation accelerators, the term we used before.
These are again various – and ever more – sets of technologies and technological innovations that drive digital transformation and all of them are inherently integrated with artificial intelligence and in reality some are even close to synonyms of AI.
Cognitive systems: an innovation accelerator
One of these innovation accelerators, as you can see in the image of the 3rd platform, are so-called cognitive systems technologies themselves.
Cognitive computing is really a term that has been popularized by mainly IBM to describe the current wave of artificial intelligence with a twist of purpose, adaptiveness, self-learning, contextuality and human interaction. Human is key in here and without a doubt also easier to digest than all those AI-related doomsday movie scenarios.
Essentially, cognitive systems analyze the huge amount of data which is created by connected devices (not just the Internet Of Things) with diagnostic, predictive and prescriptive analytics tools which observe, learn and offer insights, suggestions and even automated actions. As you probably know, a pillar of IBM’s view is IBM Watson as we’ll tackle below. The term ‘cognitive computing’ strictly speaking is a conundrum. Cognition, for instance, also includes the subconscious which is in fact a major part of cognition. Although this would bring us too far it needs to be said that IBM does make exaggerated claims about what its ‘cognitive’ platform Watson can do. Marketing indeed.
Cognitive computing and AI powering digital evolutions: from enabling IoT and making sense of unstructured big data to next stage security
Other innovation accelerators include the Internet of Things. Here as well, AI and cognitive computing or cognitive systems are omni-present.
AI and the Internet of Things
Once you start connecting everything you need APIs, connectors, information analysis technologies and “embedded intelligence”, essentially code that makes it all possible.
Moreover, the Internet of Things, which really is about automation and information (with on top of that a layer of possibilities to, for instance, enhance customer experience or make life a bit easier) adds loads of data, Big Data (one of the four pillars of the 3rd platform) to an already exploding digital data universe. The majority of all that data is unstructured and needs to be turned into knowledge and (automated) actions as good old rules-based information management approaches simply can’t handle it. Guess what is needed to make it possible and to even make all these other aspects of the Internet of Things possible? Indeed: artificial intelligence.
The future of security is intelligent too
We won’t cover all the other innovation accelerators except one: next generation security.
Do you remember that cybersecurity was – and often still is – seen as a range of “defensive” solutions and approaches (from strategies to technologies such as firewalls and anti-virus apps)? Well, that is changing.
Security is becoming more holistic, also looking at the human aspect and all elements in a changing security perimeter. But most of all: security is becoming more pro-active and technologies to predict cyberattacks before they even happen are in high demand. What do they use: indeed, artificial intelligence, not in the ‘big overlapping’ AI sense but in detecting patterns in data and acting upon this data.
Cognitive and the age of data and analytics
AI and cognitive aren’t just present in that innovation accelerator layer. It is, as said, also very present in the four pillars of the third platform that are driving and enabling digital transformationjust as they changed the ways we, businesses and consumers, behave, work and innovate.
We already mentioned Big Data in that context: ever more unstructured data. The solution: AI. Moreover Big Data as such isn’t the crux of the matter. For years we know that most of all Big Data Analytics matter. Turning data into outcomes knowledge, actions, insights etc. That analytics part is so important that IDC has called the Big Data pillar the Big Data/Analytics pillar. What is needed for these analytics? Indeed, again AI techniques. In fact, analytics is also what so-called cognitive systems are all about in a very high degree.
AI/cognitive and unstructured data/content
The picture is clear. But what does it all mean in practice? Let’s use data again.
In the end, the other pilars of the 3d platform and technologies driving digital transformation are a lot about data to. The cloud, mobility, social business and collaboration…
Unstructured and semi-structured data is fueling a renaissance in the handling and analysis of information, resulting in a new generation of tools and capabilities that promise to offer intelligent assistance, advice, and recommendations to consumers and knowledge workers around the world. IDC
We mentioned earlier how the data universe is exploding with unstructured data growing much and much faster than other data. This is, among others due to, mobile data traffic and the Internet of Things (see how it is all connected?).
This phenomenon isn’t new either and has been predicted since at least 2000. There are debates about the exact meaning of unstructured data and to what degree it is different from unstructured or semi-structured data. Simply said unstructured data is all the data you would get from IoT sensors, social media (again a link with one of the four pillars), text files and much more. Since several years it is estimated that 80 percent of data is unstructured and that percentage seems to grow as the volume of unstructured data keeps growing faster.
Various forms of data – unstructured data requires artificial intelligence to make business sense
The typical thing with unstructured data is that it doesn’t have a predefined data model as you have with data sitting in a relational database, for instance. Unstructured data and content as such has no meaning or context because in principle we don’t know what it is.
It comes in many shapes and forms and from several sources and is often text-intensive. From paper documents that need to get digitized to Twitter messages or email, also a major source of unstructured data/content. And it’s here that – again – we see various artificial intelligence techniques such as Intelligent Document Recognition or IDR, text mining, self-learning knowledge base technology, machine learning, natural language processing and the whole cognitive computing aspect come into the picture.
In fact, if you look at the page of IBM’s famous Watson platform you’ll read that, qote, “IBM Watson is a technology platform that uses natural language processing and machine learning to reveal insights from large amounts of unstructured data”. In an information management context, we find artificial intelligence in, among others, the mentioned IDR applications, self-learning systems for customer service information, information routing processes, predictive analytics and automated processes such as automated loan application classification.
The value of artificial intelligence – conclusion and next steps
Artificial intelligence is – and will be – critical for many technological and business evolutions. And, yes, it is one of many enablers of digital transformation.
Expect further articles, including a dive into the past, presence and future of AI/cognitive – and the various applications and “forms” of AI.
Because, as said artificial intelligence is not a thing. Just looking at one context where AI and cognitive are used, Intelligent Document Recognition, there are several forms of artifical intelligence such as semantic understanding, statistical clustering and classification algorithms such as SVM, Bayes and Neural-Net, as Roland Simonis explained in part three of a blog series for AIIM, reposted here, where he tackles how AI helps solve the information and Big Data challenge.
AI – Intelligent Document Recognition algorithms
For now, let’s say it’s clear there is no harm in an algorithm enabling people to find something better (in fact, if you look at how poor search intelligence still is, we’d love to so far more intelligence in it) and there is no harm in having a system that helps you process and understand information faster and better to improve anything worth improving such as customer service (with a growing usage of IDR applications and Knowledge Base technology) and , cybersecurity or people’s health, to name just a few.
But artificial intelligence, as a “whole”, is not as far as we tend to believe.
The waves of artificial intelligence: from concept and research to business reality and ethical discussion
Although some look further in the past to look at the birth of AI, the 1950s was really when the first wave started. One of the founders of artificial intelligence as a concept was US computer scientist and cognitive scientist Dr. John McCarthy. He is believed to also have coined the term and defined artificial intelligence as “the science and engineering of making intelligent machines”. After a conference in 1956, where McCarthy was present, the first wave really took off, mainly focusing on research. On top of McCarthy, many of these researchers became household names in those early research days and today still are. Among them: Marvin Minsky, Herbert Simon and Allenn Newell, to name a few.
McCarthy’s ideas and those of his peers, as well as years of research and initial developments next led to the second wave of artificial intelligence in the 1980s, mainly due to the success of expert systems, among others strengthened by the rise of the PC and the client-server model.
A third wave took place at the end of the nineties and early 2000 when there was more attention from the perspective of specific applications of AI across diverse domains. On top of that, there was the success of the Internet, which also led to quite some hype and predictions that didn’t really live up to their promises. The spreading availability and usage of the Internet did cause a stir. In those days we worked for a publishing house, as publishers, and one of the company’s major magazines, Inside Internet, had several pieces from AI researchers from various universities where real-life applications were tried. Artificial intelligence was again debated a lot and became popular, also in globally launched magazines in those days such as Wired.
Unfortunately, the hype was big again too. It’s also in those days that the convergence of man and machine became increasing popular(ized). In 1999, for instance, we had the chance to interview Joël de Rosnay who had published a book of a nascent global super organism, the cybiont, which would know a “symbiotic mankind” in a connected ecosystem of humans, technology and everything really. It does sound familiar now, doesn’t it? More about de Rosnay’s and views – and those of others – that show how increasing interconnectedness was seen as the big promise back then in this article.
Today’s artificial intelligence wave is one of rapid adoption of AI technologies in new applications, driven by, among others the mentioned 3rd platform technologies, including the cloud, faster processing capabilities, scalability, Big Data, the push of various companies in a space where technologies continue to be refined across several applications and industries (self-driving cars, robotics, the Internet of Things, the rise of chatbots and more) and, last but not least, market demand for smart and intelligent technologies to leverage the potential of new technologies, information and digital transformation.
Whether this wave will lead to true and continuing business momentum however remains to be seen despite “good signs”, as is the next wave and the increasing number of dicussions on the “ethics”, security and “place” of AI in the future. The “AI and robots taking over mankind view” and superintelligence evolutions – instead of AI as mimicking possibilities of the human brain for a purpose – are real concerns and deserve attention.
It’s clear that artificial intelligence is indeed not new but has changed a lot and gains more attention than ever. It’s becoming ubiquitous and transforms the way we work, live and do business. Along with robotics (and phenomena such as 3D printing, the Internet of Things, etc.), artificial intelligence is again an increasingly debated topic. Still, this wave is not the last one, it is even very similar in many regards to the previous one and the hype is loud.
Intelligence and artificial intelligence – what’s in a name?
There are many definitions of artificial intelligence, just as there are many definitions of intelligence.
The Encyclopædia Britannica defines artificial intelligence as, quote, “the ability of a digital computer or computer-controlled robot to perform tasks commonly associated with intelligent beings. The term is frequently applied to the project of developing systems endowed with the intellectual processes characteristic of humans, such as the ability to reason, discover meaning, generalize, or learn from past experience”. It goes on defining what intelligence means, a phenomenon that has fascinated us since ancient times and now, more than ever, is discussed in these digital times where the pace at which AI gets used is growing fast. There are different technologies that get ranked as artificial intelligence and different types of AI. The article gives a good overview of the history of AI and touches upon topics such as reasoning, perception and problem solving. The growth of artificial intelligence is not linear but exponential and therefore it’s good to look at all the domains where it’s used and can be used in an open debate.
Google recently open sourced TensorFlow providing access to a powerful machine learning system. TensorFlow is a machine learning library with tools for data scientists to design intelligent systems (interface for expressing machine learning algorithms and implementation for executing such algorithms). It runs on CPUs or GPUs, and on desktop, server, laptop, or mobile platforms with a single API. See paper here.
Originally developed by the Google Brain Team in Machine Intelligence Research, TensorFlow has a flexible, portable and general architecture for a wide variety of applications. The system has been used for deploying machine learning systems for information retrieval, simulations, speech recognition, computer vision, robotics, natural language processing, geographic information extraction, and computational drug discovery.
The system uses data flow graphs where data with multiple dimensions (values) are passed along from mathematical computation to mathematical computation. Complex bits of data are tensors and math-y bits are nodes, and tensors flow through the graph of nodes. The way data transforms from node to node tells the system relationships in the data.
What is really cool is the systems flexibility and simplicity with ability to quickly experiment with different ideas on the laptop, easily move into production, use GPUs with no code changes, and deploy on a mobile device.
The ability to simply and easily deploy products on mobile devices is a valuable feature. It can be used on a wide variety of heterogeneous systems, including large-scale distributed systems.
TensorFlow has an Apache 2.0 open source license for use commercially.
We asked 19 executives involved in different IoT companies this question. Their answers predict a future of completely connected devices and real-time access to virtually any data imaginable for completely informed decision making.
Here’s what they said:
We’ll overestimate what it can do in 10 years and underestimate what it can do in 20. More seamless interaction. We’re removing humanity—in some places this is good, in others? (e.g., electronic seal with alzheimers patient versus a real person).
The ability to aggregate and analyze disparate data. Whatever you can monitor/measure and imagine, you’ll be able to do.
We are currently at the Internet of Thing. Every manufacturer is creating a single product. We have to go across manufacturers and start talking to one another. This is two to five years aways.
The market is endless. It’s exciting. Build great software with a sophisticated backend with multiple security levels like Cisco is offering. Bring order and sophistication to data. Security is currently 10th on the list. It needs to be in the top five. Security is an art that involves cryptography. Most companies don’t have the talent they need to develop secure products.
Very wild west. Major players will emerge. Platform wars will enable a vast network of sensors to work together. A dominant platform will emerge. There are a lot of custom platforms right now. We’ll see more standardization of platforms and more plug and play. Right now everyone is doing different things for different reasons - raw socket versus HTTP requests. Things will standardize over time. Ten years ago I worked on a vehicle management system that, today, has evolved to more standardized common protocol for a more reliable and scalable infrastructure. Hardware manufacturers that make server boards are now doing distributed processing because data is not going to a centralized location. There’s so much data, you have to decide what’s relevant to keep.
It’s becoming ubiquitous. In 10 years, anything that needs to be connected will have the ability to be present on the internet.
We will have 25 to 50 billion connected devices which will connect via a mesh network. This will bring global, ubiquitous access to data and will make the life of telcos more difficult. Google is looking in to ubiquitous wi-fi - the devices can connect to the network or range of devices through a decentralized mesh network. Cloud networks are expanding. The global cloud will have all devices residing there. Render connected devices provide computational power to someone on the other side of the world.
More and more devices are connected to each other via APTs. Connect all the things that you want. Drive to your home, garage door opens without pressing a button, coffee starts, heat adjusts, etc.
We’re just seeing the tip of the iceberg. Adoption of technology is a fraction of what it will be.
Piece of human computer interaction. Bigger than putting things on the internet. Make it understandable, understanding, enhance humanity. Make IoT move in a more humanistic way.
Unified ecosystem of all devices where companies talk to each other. There has to be a standard. Maybe it’s established by Apple or Google because of the size of their user bases.
We will continue to see the evolution of personal devices - glasses, watches, personal devices, home devices. Hardware will connect everything. This will be led at the enterprise level by the IBMs and Ciscos. I’m not as close to the enterprise level. Will introduce to Belkin and Fitbit.
The ability to use data from devices to make intelligent, informed decisions.
Using data to iterate your products quickly while they’re in the customers’ hands.
Creating a smarter world. Companies not working in silos. Open to other partners, providers and vendors to promote the sharing of information, automation and best practices.
It’s exciting. We haven’t even started to fully understand the possibilities of getting remote control via the phone. Learning patterns will automatically adjust over time and people will see new possibilities.
Visibility and reliability. The percent of industrial equipment that is currently connected is between one and 25% depending on the company. There’s tremendous opportunity to connect equipment. Likewise, the probability of detecting an important event without false positives is about 30%, except at GE where we’re a world class 99%. The ability to tell what’s wrong and to diagnose a solution is nowhere near 99%. We’re probably at 30% right now. We must improve the model of the machine and the people that interacted with it and what they did. When we’re able to capture more information on the machines and the people, we’ll move from anomaly detection to correction. Providing better operational data to the cloud will help us improve operational optimization.
It will evolve like other IT. Wildly hyped and then clocked and scaled over the next five to seven years. The next frontier will be more customer centric. We’re currently working with a commercial carpet manufacturer putting RFID chips in squares of carpet to see traffic patterns in stores.
Problem: You will have a CDR (Call Details Record) file, you need to find out top customers facing frequent call drops in Roaming. This is a very important report which telecom companies use to prevent customer churn out, by calling them back and at the same time contacting their roaming partners to improve the connectivity issues in specific areas.
//First we’ll read the data from the csv file
val sc = new SparkContext(new SparkConf().setAppName("CallDetailsProblem ").setMaster("local[2]"))
val logFile = "/home/om_workspace/test.csv"
val text = sc.textFile(logFile)
//As we’re dealing with a CSV file with no headers it’s a good idea to define a case class that defines the schema
//define the schema using a case class
case class Call(visitor_locn: String, call_duration:
Integer, phone_no: String, error_code: String)
//Then create a RDD of Calls
val calls = text.map(_.split(",")).map(p =>
Call(p(0),p(1).toInt,p(2),p(3)))
println(calls.count());
calls.foreach {
x => println(x)
}
var result = calls.map(x => (x.visitor_locn,1)).reduceByKey(_+_).collect.sortBy(_._2);
// println(result.reverse.mkString("\n"));
//Number of different customers having errors:
var result2 = calls.map(x => (x.error_code,1)).reduceByKey(_+_).collect.sortBy(_._2);
println(result2.reverse.mkString("\n"));
In 2003, Herb Sutter exposed the industry's biggest "dirty little secret" with his "The Free Lunch Is Over" article, demonstrating clearly that the era of ever-faster processors was at an end, to be replaced by a new era of parallelism via "cores" (virtual CPUs) on a single chip. The revelation sent shockwaves through the programming community because getting thread-safe code correct has always remained, in theory if not in practice, the province of high-powered software developers way too expensive for your company to hire. A privileged few, it seemed, understood enough about Java's threading model and concurrency APIs and "synchronized" keyword to write code that both provided safety and throughput ... and most of those had learned it the hard way.
It is presumed that the rest of the industry was left to fend for itself, clearly not a desirable conclusion, at least not to the IT departments paying for that software being developed.
Back-to-concurrency basicsLike Scala's sister language in the .NET space, F#, Scala stands as one of several purported solutions to the "concurrency problem." In this column, I have touched on several of Scala's properties that make it more amenable to writing thread-safe code such as immutable objects by default and a design preference for returning copies of objects rather than modifying their contents. Scala's support for concurrency reaches far deeper than just this though; it's high time to start poking around in the Scala libraries to see what lives there.
Before we can get too deep into Scala's concurrency support, it's a good idea to make sure that you have a good understanding of Java's basic concurrency model because Scala's support for concurrency builds, at some level, on top of the features and functionality provided by the JVM and supporting libraries. Toward that end, the code in Listing 1 contains a basic concurrency problem known as the Producer/Consumer problem (as described in the "Guarded Blocks" section of the Sun Java Tutorial). Note that the Java Tutorial version doesn't use thejava.util.concurrent classes in its solution, preferring instead to use the old wait()/notifyAll() methods from java.lang.Object:
Listing 1. Producer/Consumer (pre-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)
{
Drop drop = new Drop();
(new Thread(new Producer(drop))).start();
(new Thread(new Consumer(drop))).start();
}
}
The Java Tutorial "bug"
Curious readers will probably go and compare this code against that found in the Java Tutorial to see what the difference is; those who do will discover that instead of simply "synchronized"-ing the put and takemethods, I've instead used a lock object stored inside the Drop. The reason for this is simple: The monitor of an object is never encapsulated inside of the class, so as written the Java Tutorial version allows this (obviously insane) code to break it:
public class ProdConSample { public static void main(String[] args) { Drop drop = new Drop(); (new Thread(new Producer(drop))).start(); (new Thread(new Consumer(drop))).start(); synchronized(drop) { Thread.sleep(60 * 60 * 24 * 365 * 10); // sleep for 10 years?!? } } }
By using a private object as the monitor on which the lock is based, this code will have no effect. In essence, now the thread-safety implementation is encapsulated; before it relied on client goodwill to work correctly.
Note: The code I present here is slightly modified from the Sun tutorial solution; there's a small design flaw in the code they present (see The Java Tutorial "bug").
The core of the Producer/Consumer problem is a simple one to understand: one (or more) producer entities want to provide data for one (or more) consumer entities to consume and do something with (in this case it consists of printing the data to the console). The Producer andConsumer classes are pretty straightforward Runnable-implementing classes: TheProducer takes Strings from an array and puts them into a buffer for the Consumer totake as desired.
The hard part of the problem is that if the Producer runs too fast, data will be potentially lost as it is overwritten; if the Consumer runs too fast, data will be potentially double-processed as the Consumer reads the same data twice. The buffer (called the Drop in the Java Tutorial code) must ensure that neither condition occurs. Not to mention that there is no potential for data corruption (hard in the case of String references, but still a concern) as messages are putin and taken out of the buffer.
A full discussion of the subject is best left to Brian Goetz's Java Concurrency in Practice or Doug Lea's earlier Concurrent Programming in Java (see Resources), but a quick rundown of how this code works is necessary before you apply Scala to it.
When the Java compiler sees the synchronized keyword, it generates a try/finallyblock in place of the synchronized block with a monitorenter opcode at the top of the block and a monitorexit opcode in the finally block to ensure that the monitor (the Java basis for atomicity) is released regardless of how the code exits. Thus, the put code in Drop gets rewritten to look like Listing 2:
Listing 2. Drop.put after compiler helpfulness
// This is pseudocode
public void put(String message)
{
try
{
monitorenter(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();
}
finally
{
monitorexit(lock)
}
}
The wait() method tells the current thread to go into an inactive state and wait for another thread to call notifyAll() on that object. The thread just notified must then attempt to acquire the monitor again after which point it is free to continue execution. In essence, wait() andnotify()/notifyAll() act as a simple signaling mechanism, allowing the Drop to coordinate between the Producer and the Consumerthreads, one take to each put.
The code download that accompanies this article uses the Java5 concurrency enhancements (the Lock and Condition interfaces and theReentrantLock lock implementation) to provide timeout-based versions of Listing 2, but the basic code pattern remains the same. That is the problem: Developers who write code like in Listing 2 have to focus too exclusively on the details, the low-level implementation code, of the threading and locking required to make it all work correctly. What's more, developers have to reason about each and every line in the code, looking to see if it needs to be protected because too much synchronization is just as bad as too little.
Now let's look at Scala alternatives.
Good old Scala concurrency (v1)
One way to start working with concurrency in Scala is to simply translate the Java code directly over to Scala, taking advantage of Scala's syntax in places to simplify the code, a least a little:
Listing 3. ProdConSample (Scala)
object ProdConSample
{
class Producer(drop : Drop)
extends Runnable
{
val importantInfo : Array[String] = Array(
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
);
override def run() : Unit =
{
importantInfo.foreach((msg) => drop.put(msg))
drop.put("DONE")
}
}
class Consumer(drop : Drop)
extends Runnable
{
override def run() : Unit =
{
var message = drop.take()
while (message != "DONE")
{
System.out.format("MESSAGE RECEIVED: %s%n", message)
message = drop.take()
}
}
}
class Drop
{
var message : String = ""
var empty : Boolean = true
var lock : AnyRef = new Object()
def put(x: String) : Unit =
lock.synchronized
{
// Wait until message has been retrieved
await (empty == true)
// Toggle status
empty = false
// Store message
message = x
// Notify consumer that status has changed
lock.notifyAll()
}
def take() : String =
lock.synchronized
{
// Wait until message is available.
await (empty == false)
// Toggle status
empty=true
// Notify producer that staus has changed
lock.notifyAll()
// Return the message
message
}
private def await(cond: => Boolean) =
while (!cond) { lock.wait() }
}
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop();
// Spawn Producer
new Thread(new Producer(drop)).start();
// Spawn Consumer
new Thread(new Consumer(drop)).start();
}
}
The Producer and Consumer classes are almost identical to their Java cousins, again extending (implementing) the Runnable interface and overriding the run() method, and — in Producer's case — using the built-in iteration method for each to walk the contents of theimportantInfo array. (Actually, to make it more like Scala, importantInfo should probably be a List instead of an Array, but in this first pass, I want to keep things as close to the original Java code as possible.)
The Drop class also looks similar to the Java version except that in Scala, "synchronized" isn't a keyword, it's a method defined on the classAnyRef, the Scala "root of all reference types." This means that to synchronize on a particular object, you simply call the synchronize method on that object; in this case, on the object held in the lock field on Drop.
Note that we also make use of a Scala-ism in the Drop class in the definition of the await() method: The cond parameter is a block of code waiting to be evaluated rather than evaluated prior to being passed in to the method. Formally in Scala, this is known as "call-by-name"; here it serves as a useful way of capturing the conditional-waiting logic that had to be repeated twice (once in put, once in take) in the Java version.
Finally, in main(), you create the Drop instance, instantiate two threads, kick them off with start(), and then simply fall off of the end ofmain(), trusting that the JVM will have started those two threads before you finish with main(). (In production code, this probably shouldn't be taken for granted, but for a simple example like this, it's going to be OK 99.99 percent of the time. Caveat emptor.)
However, having said all that, the same basic problem remains: Programmers still have to worry way too much about the issues of signaling and coordinating the two threads. While some of the Scala-isms might make the syntax easier to live with, it's not really an incredibly compelling win so far.
Scala concurrency, v2
A quick look at the Scala Library Reference reveals an interesting package: scala.concurrency. This package contains a number of different concurrency constructs, including the first one we're going to make use of, the MailBox class.
As its name implies, MailBox is essentially the Drop by itself, a single-slot buffer that holds a piece of data until it has been retrieved. However, the big advantage of MailBox is that it completely encapsulates the details of the sending and receiving behind a combination of pattern-matching and case classes, making it more flexible than the simple Drop (or the Drop's big multi-slot data-holding brother,java.util.concurrent.BoundedBuffer).
Listing 4. ProdConSample, v2 (Scala)
package com.tedneward.scalaexamples.scala.V2
{
import concurrent.{MailBox, ops}
object ProdConSample
{
class Producer(drop : Drop)
extends Runnable
{
val importantInfo : Array[String] = Array(
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
);
override def run() : Unit =
{
importantInfo.foreach((msg) => drop.put(msg))
drop.put("DONE")
}
}
class Consumer(drop : Drop)
extends Runnable
{
override def run() : Unit =
{
var message = drop.take()
while (message != "DONE")
{
System.out.format("MESSAGE RECEIVED: %s%n", message)
message = drop.take()
}
}
}
class Drop
{
private val m = new MailBox()
private case class Empty()
private case class Full(x : String)
m send Empty() // initialization
def put(msg : String) : Unit =
{
m receive
{
case Empty() =>
m send Full(msg)
}
}
def take() : String =
{
m receive
{
case Full(msg) =>
m send Empty(); msg
}
}
}
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop()
// Spawn Producer
new Thread(new Producer(drop)).start();
// Spawn Consumer
new Thread(new Consumer(drop)).start();
}
}
}
The only difference here between v2 and v1 is in the implementation of Drop, which now makes use of the MailBox class to handle the blocking and signaling of messages coming in and being removed from the Drop. (We could have rewritten Producer and Consumer to use the MailBoxdirectly, but for simplicity's sake, I assume that we want to keep the Drop API consistent across all the examples.) Using a MailBox is a bit different from the classic BoundedBuffer (Drop) that we've been using, so let's walk through that code in detail.
MailBox has two basic operations: send and receive. The receiveWithin method is simply a timeout-based version of receive. MailBoxtakes messages that can be of any type whatsoever. The send() method essentially drops the message into the mailbox, notifying any pending receivers immediately if it's of a type they care about, and appending it to a linked list of messages for later retrieval. The receive() method blocks until a message appropriate to the function block that's passed in to it is received.
Therefore, in this situation, we create two case classes, one containing nothing (Empty) that indicates the MailBox is empty and one containing the data (Full) with the message data in it.
The put method, because it is putting data into the Drop, calls receive() on the MailBox looking for an Empty instance, thus blocking untilEmpty has been sent. At this point, it sends a Full instance to the MailBox containing the new data.
The take method, because it is removing data from the Drop, calls receive() on the MailBox looking for a Full instance, extracts the message (again thanks to pattern-matching's ability to extract values from inside the case class and bind them to local variables), and sends anEmpty instance to the MailBox.
No explicit locking required, and no thinking about monitors.
Scala concurrency, v3
In fact, we can shorten the code up considerably if it turns out that Producer and Consumer don't really have to be full-fledged classes at all (which is the case here) — both are essentially thin wrappers around the Runnable.run() method, which Scala can do away with entirely by using the scala.concurrent.ops object's spawn method, like in Listing 5:
Listing 5. ProdConSample, v3 (Scala)
package com.tedneward.scalaexamples.scala.V3
{
import concurrent.MailBox
import concurrent.ops._
object ProdConSample
{
class Drop
{
private val m = new MailBox()
private case class Empty()
private case class Full(x : String)
m send Empty() // initialization
def put(msg : String) : Unit =
{
m receive
{
case Empty() =>
m send Full(msg)
}
}
def take() : String =
{
m receive
{
case Full(msg) =>
m send Empty(); msg
}
}
}
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop()
// Spawn Producer
spawn
{
val importantInfo : Array[String] = Array(
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
);
importantInfo.foreach((msg) => drop.put(msg))
drop.put("DONE")
}
// Spawn Consumer
spawn
{
var message = drop.take()
while (message != "DONE")
{
System.out.format("MESSAGE RECEIVED: %s%n", message)
message = drop.take()
}
}
}
}
}
The spawn method (imported via the ops object just at the top of the package block) takes a block of code (another by-name parameter example) and wraps it inside the run() method of an anonymously-constructed thread object. In fact, it's not too difficult to understand what spawn's definition looks like inside of the ops class:
Listing 6. scala.concurrent.ops.spawn()
def spawn(p: => Unit) = {
val t = new Thread() { override def run() = p }
t.start()
}
... which once again highlights the power of by-name parameters.
One drawback to the ops.spawn method is the basic fact that it was written in 2003 before the Java 5 concurrency classes had taken effect. In particular, the java.util.concurrent.Executor and its ilk were created to make things easier for developers to spawn threads without having to actually handle the details of creating thread objects directly. Fortunately, spawn's definition is simple enough to recreate in a custom library of your own, making use of Executor (or ExecutorService or ScheduledExecutorService) to do the actual launching of the thread.
In fact, Scala's support for concurrency goes well beyond the MailBox and ops classes; Scala also supports a similar concept called "Actors," which uses a similar kind of message-passing approach that the MailBox uses, but to a much greater degree and with much more flexibility. But that's for next time.
Conclusion
Scala provides two levels of support for concurrency, much as it does for other Java-related topics:
The first, full access to the underlying libraries (such as java.util.concurrent) and support for the "traditional" Java concurrency semantics (such as monitors and wait()/notifyAll()).
The second, a layer of abstraction on top of those basic mechanics, as exemplified by the MailBox class discussed in this article and the Actors library that we'll discuss in the next article in the series.
The goal is the same in both cases: to make it easier for developers to focus on the meat of the problem rather than having to think about the low-level details of concurrent programming (obviously the second approach achieves that better than the first, at least to those who aren't too deeply invested in thinking at the low-level primitives level).
One clear deficiency to the current Scala libraries, however, is the obvious lack of Java 5 support; the scala.concurrent.ops class should have operations like spawn that make use of the new Executor interfaces. It should also support versions of synchronized that make use of the new Lock interfaces. Fortunately, these are all library improvements that can be done at any point during Scala's life cycle without breaking existing code; they can even be done by Scala developers themselves without having to wait for Scala's core development team to provide it to them (all it takes is a little time).