The document discusses patterns and anti-patterns for multithreaded programming. It begins with an example of improper "double-checked locking" on a collection and provides fixes. It then covers patterns for scenarios with many readers and few writers, such as using synchronized data structures, concurrent collections, ReadWriteLock, or "copy-on-write". Examples are given for each approach. The document also mentions covering patterns for many writers and few readers before closing.
Big Data Everywhere Chicago: Unleash the Power of HBase Shell (Conversant) BigDataEverywhere
Jayesh Thakrar, Senior Systems Engineer, Conversant
The venerable HBase shell is often regarded as a simple utility to perform basic DDL and maintenance activities. However, it is in fact a powerful, interactive programming environment, primarily due to the JRuby engine under the covers. In this presentation, I'll describe its JRuby heritage and show some of the things that can be done with the "ird" (interactive ruby shell), as well as show how to exploit JRuby and Java integration via concrete working examples. In addition, I will demonstrate how the "shell" can be used in Hadoop streaming to quickly perform complex and large volume batch jobs.
Fast as C: How to Write Really Terrible JavaCharles Nutter
For years we’ve been told that the JVM’s amazing optimizers can take your running code and make it “fast” or “as fast as C++” or “as fast as C”…or sometimes “faster than C”. And yet we don’t often see this happen in practice, due in large part to (good and bad) development patterns that have taken hold in the Java world.
In this talk, we’ll explore the main reasons why Java code rarely runs as fast as C or C++ and how you can write really bad Java code that the JVM will do a better job of optimizing. We’ll take some popular microbenchmarks and burn them to the ground, monitoring JIT logs and assembly dumps along the way.
Big Data Everywhere Chicago: Unleash the Power of HBase Shell (Conversant) BigDataEverywhere
Jayesh Thakrar, Senior Systems Engineer, Conversant
The venerable HBase shell is often regarded as a simple utility to perform basic DDL and maintenance activities. However, it is in fact a powerful, interactive programming environment, primarily due to the JRuby engine under the covers. In this presentation, I'll describe its JRuby heritage and show some of the things that can be done with the "ird" (interactive ruby shell), as well as show how to exploit JRuby and Java integration via concrete working examples. In addition, I will demonstrate how the "shell" can be used in Hadoop streaming to quickly perform complex and large volume batch jobs.
Fast as C: How to Write Really Terrible JavaCharles Nutter
For years we’ve been told that the JVM’s amazing optimizers can take your running code and make it “fast” or “as fast as C++” or “as fast as C”…or sometimes “faster than C”. And yet we don’t often see this happen in practice, due in large part to (good and bad) development patterns that have taken hold in the Java world.
In this talk, we’ll explore the main reasons why Java code rarely runs as fast as C or C++ and how you can write really bad Java code that the JVM will do a better job of optimizing. We’ll take some popular microbenchmarks and burn them to the ground, monitoring JIT logs and assembly dumps along the way.
There is hardly a Senior Java developer who has never heard of sun.misc.Unsafe. Though it has always been a private API intended for JDK internal use only, the popularity of Unsafe has grown too fast, and now it is used in many open-source projects. OK.RU is not an exception: its software also heavily relies on Unsafe APIs.
During this session we'll try to understand what is so attractive about Unsafe. Why do people keep using it regardless the warnings of removal from future JDK releases? Are there any safe alternatives to private API or is it absolutely vital? We will review the typical cases when Java developers prefer to go unsafe and discuss major benefits and the drawbacks of it. The report will be supported by the real examples from OK.RU experience.
The latest slide deck about Java NIO.2 from *instinctools Java developer Alexandr Brui. You can find here Java NIO.2 design, work with data, selector & channels, reading & writing and many more.
Java ME - 06 - Record Stores, Distribution and LocalizationAndreas Jakl
Almost every application needs to store data — e.g. for saving user preferences, highscores or login data. This module explains the concepts behind the record stores, the only way to save data that is included in the MIDP specification and therefore supported on all phones. Data access can be handled conveniently using the DataInputStream and DataOutputStream-classes.This module also covers how to distribute your applications using different project configurations in NetBeans; a process which can involve pre-processing, selective resource inclusion as well as obfuscation. As mobile phones are available on a global market, localization is also a very important aspect. The challenge involves extending the game from the last course so that the game can save the highscore and can be deployed on phones with different screen sizes using specialized graphics.
Contents:
* Record Stores
o Input/OutputStreams
* Distribution
*
o Deployment
o Pre-Processing
o Obfuscation
o OTA-Deployment
* Localization
I used these slides for a Scala workshop that I gave. They are based on these: http://www.scala-lang.org/node/4454. Thanks to Alf Kristian Støyle and Fredrik Vraalsen for sharing!
There is hardly a Senior Java developer who has never heard of sun.misc.Unsafe. Though it has always been a private API intended for JDK internal use only, the popularity of Unsafe has grown too fast, and now it is used in many open-source projects. OK.RU is not an exception: its software also heavily relies on Unsafe APIs.
During this session we'll try to understand what is so attractive about Unsafe. Why do people keep using it regardless the warnings of removal from future JDK releases? Are there any safe alternatives to private API or is it absolutely vital? We will review the typical cases when Java developers prefer to go unsafe and discuss major benefits and the drawbacks of it. The report will be supported by the real examples from OK.RU experience.
The latest slide deck about Java NIO.2 from *instinctools Java developer Alexandr Brui. You can find here Java NIO.2 design, work with data, selector & channels, reading & writing and many more.
Java ME - 06 - Record Stores, Distribution and LocalizationAndreas Jakl
Almost every application needs to store data — e.g. for saving user preferences, highscores or login data. This module explains the concepts behind the record stores, the only way to save data that is included in the MIDP specification and therefore supported on all phones. Data access can be handled conveniently using the DataInputStream and DataOutputStream-classes.This module also covers how to distribute your applications using different project configurations in NetBeans; a process which can involve pre-processing, selective resource inclusion as well as obfuscation. As mobile phones are available on a global market, localization is also a very important aspect. The challenge involves extending the game from the last course so that the game can save the highscore and can be deployed on phones with different screen sizes using specialized graphics.
Contents:
* Record Stores
o Input/OutputStreams
* Distribution
*
o Deployment
o Pre-Processing
o Obfuscation
o OTA-Deployment
* Localization
I used these slides for a Scala workshop that I gave. They are based on these: http://www.scala-lang.org/node/4454. Thanks to Alf Kristian Støyle and Fredrik Vraalsen for sharing!
Scala is a general purpose programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It has established itself as one of the main alternative languages on the Java Virtual Machine, being used by companies like Twitter and LinkedIn. Scala fuses functional programming (from which it borrows higher-order functions and closures, generic typing and immutable data structures) and object-oriented programming programming (from which it takes inheritance and encapsulation). It interoperates fully with Java, allowing a smooth transition and access to all existing Java libraries.
Scala’s lightweight syntax makes it easy to extend the language through DSLs. In this talk we are going to have a quick overview of Scala’s main features (closures, higher-order functions, implicits), and collection classes in the standard library. We’ll see how a new concurrency model, such as actors, can be added to the language through a library.
Scalable and Flexible Machine Learning With Scala @ LinkedInVitaly Gordon
The presentation given by Chris Severs and myself at the Bay Area Scala Enthusiasts meetup. http://www.meetup.com/Bay-Area-Scala-Enthusiasts/events/105409962/
Scala er et Java-relateret, statisk typet programmeringssprog i hastig fremmarch. Sproget kombinerer aspekter fra objekt- og funktionsorienterede sprog og fokuserer på skalerbarhed og effektivitet, både på det kodemæssige og afviklingsmæssige niveau. Syntaksen er elegant og koncis. Samtidig indeholder sproget stærke konstruktioner til understøttelse af parallelle applikationer, der udnytter fremtidens hardwarearkitekturer.
Java som sprog har ikke bevæget sig meget de seneste år. Vi har stadig ikke closures eller funktionelle aspekter som f.eks. C# har haft siden version 3. Er Scala svaret på enhver Javaudviklers bønner eller er sproget kun interessant for tågehoveder som mig, som begynder at synes bedre og bedre om funktionsorientering? Er den store portion syntaktisk sukker, Scala bringer på bordet, bare tomme kalorier?
Transcript: Selling digital books in 2024: Insights from industry leaders - T...BookNet Canada
The publishing industry has been selling digital audiobooks and ebooks for over a decade and has found its groove. What’s changed? What has stayed the same? Where do we go from here? Join a group of leading sales peers from across the industry for a conversation about the lessons learned since the popularization of digital books, best practices, digital book supply chain management, and more.
Link to video recording: https://bnctechforum.ca/sessions/selling-digital-books-in-2024-insights-from-industry-leaders/
Presented by BookNet Canada on May 28, 2024, with support from the Department of Canadian Heritage.
State of ICS and IoT Cyber Threat Landscape Report 2024 previewPrayukth K V
The IoT and OT threat landscape report has been prepared by the Threat Research Team at Sectrio using data from Sectrio, cyber threat intelligence farming facilities spread across over 85 cities around the world. In addition, Sectrio also runs AI-based advanced threat and payload engagement facilities that serve as sinks to attract and engage sophisticated threat actors, and newer malware including new variants and latent threats that are at an earlier stage of development.
The latest edition of the OT/ICS and IoT security Threat Landscape Report 2024 also covers:
State of global ICS asset and network exposure
Sectoral targets and attacks as well as the cost of ransom
Global APT activity, AI usage, actor and tactic profiles, and implications
Rise in volumes of AI-powered cyberattacks
Major cyber events in 2024
Malware and malicious payload trends
Cyberattack types and targets
Vulnerability exploit attempts on CVEs
Attacks on counties – USA
Expansion of bot farms – how, where, and why
In-depth analysis of the cyber threat landscape across North America, South America, Europe, APAC, and the Middle East
Why are attacks on smart factories rising?
Cyber risk predictions
Axis of attacks – Europe
Systemic attacks in the Middle East
Download the full report from here:
https://sectrio.com/resources/ot-threat-landscape-reports/sectrio-releases-ot-ics-and-iot-security-threat-landscape-report-2024/
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...UiPathCommunity
💥 Speed, accuracy, and scaling – discover the superpowers of GenAI in action with UiPath Document Understanding and Communications Mining™:
See how to accelerate model training and optimize model performance with active learning
Learn about the latest enhancements to out-of-the-box document processing – with little to no training required
Get an exclusive demo of the new family of UiPath LLMs – GenAI models specialized for processing different types of documents and messages
This is a hands-on session specifically designed for automation developers and AI enthusiasts seeking to enhance their knowledge in leveraging the latest intelligent document processing capabilities offered by UiPath.
Speakers:
👨🏫 Andras Palfi, Senior Product Manager, UiPath
👩🏫 Lenka Dulovicova, Product Program Manager, UiPath
The Art of the Pitch: WordPress Relationships and SalesLaura Byrne
Clients don’t know what they don’t know. What web solutions are right for them? How does WordPress come into the picture? How do you make sure you understand scope and timeline? What do you do if sometime changes?
All these questions and more will be explored as we talk about matching clients’ needs with what your agency offers without pulling teeth or pulling your hair out. Practical tips, and strategies for successful relationship building that leads to closing the deal.
Accelerate your Kubernetes clusters with Varnish CachingThijs Feryn
A presentation about the usage and availability of Varnish on Kubernetes. This talk explores the capabilities of Varnish caching and shows how to use the Varnish Helm chart to deploy it to Kubernetes.
This presentation was delivered at K8SUG Singapore. See https://feryn.eu/presentations/accelerate-your-kubernetes-clusters-with-varnish-caching-k8sug-singapore-28-2024 for more details.
DevOps and Testing slides at DASA ConnectKari Kakkonen
My and Rik Marselis slides at 30.5.2024 DASA Connect conference. We discuss about what is testing, then what is agile testing and finally what is Testing in DevOps. Finally we had lovely workshop with the participants trying to find out different ways to think about quality and testing in different parts of the DevOps infinity loop.
GraphRAG is All You need? LLM & Knowledge GraphGuy Korland
Guy Korland, CEO and Co-founder of FalkorDB, will review two articles on the integration of language models with knowledge graphs.
1. Unifying Large Language Models and Knowledge Graphs: A Roadmap.
https://arxiv.org/abs/2306.08302
2. Microsoft Research's GraphRAG paper and a review paper on various uses of knowledge graphs:
https://www.microsoft.com/en-us/research/blog/graphrag-unlocking-llm-discovery-on-narrative-private-data/
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
Keynote at DIGIT West Expo, Glasgow on 29 May 2024.
Cheryl Hung, ochery.com
Sr Director, Infrastructure Ecosystem, Arm.
The key trends across hardware, cloud and open-source; exploring how these areas are likely to mature and develop over the short and long-term, and then considering how organisations can position themselves to adapt and thrive.
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Jeffrey Haguewood
Sidekick Solutions uses Bonterra Impact Management (fka Social Solutions Apricot) and automation solutions to integrate data for business workflows.
We believe integration and automation are essential to user experience and the promise of efficient work through technology. Automation is the critical ingredient to realizing that full vision. We develop integration products and services for Bonterra Case Management software to support the deployment of automations for a variety of use cases.
This video focuses on the notifications, alerts, and approval requests using Slack for Bonterra Impact Management. The solutions covered in this webinar can also be deployed for Microsoft Teams.
Interested in deploying notification automations for Bonterra Impact Management? Contact us at sales@sidekicksolutionsllc.com to discuss next steps.
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf91mobiles
91mobiles recently conducted a Smart TV Buyer Insights Survey in which we asked over 3,000 respondents about the TV they own, aspects they look at on a new TV, and their TV buying preferences.
2. Agenda
Introduction
Patterns & anti-patterns
Warm-up: “double-checked locking” on collections
Many readers, few writers
Many writers, few readers
Bonus: configuring a ThreadPoolExecutor
Closing...
2
3. Introduction
The main goal is two-fold: correctness first, and
performance/scalability next
Problems tend to repeat themselves: anti-patterns work as
visual “crutches” to spot bad smell
3
4. Agenda
Introduction
Patterns & anti-patterns
Warm-up: “double-checked locking” on collection
Many readers, few writers
Many writers, few readers
Bonus: configuring a ThreadPoolExecutor
Closing...
4
5. “Double-checked locking” on collection
Initialize a collection lazily
class
Unsafe
{
private
Map<String,Object>
map
=
null;
public
void
useMap()
{
if
(map
==
null)
{
initMap();
}
//
read
the
map;
get(),
iterate,
...
}
private
synchronized
void
initMap()
{
if
(map
==
null)
{
map
=
new
HashMap<String,Object>();
//
populate
the
map
with
initial
data
}
}
}
5
6. “Double-checked locking” on collection
It’s worse than the real double-checked locking pattern
Why would one do this?
Delay the expensive operation of populating the data
You don’t want to incur penalty on reads: once the map is set
up, it’s read-only
But is laziness really necessary?
6
7. “Double-checked locking” on collection
“Eager” fix
class
Safe
{
private
final
Map<String,Object>
map;
public
Safe()
{
map
=
new
HashMap<String,Object>();
//
populate
the
map
with
initial
data
}
public
void
useMap()
{
//
read
the
map;
get(),
iterate,
...
}
}
7
8. “Double-checked locking” on collection
Fix using volatile if the data is optional & large
class
Safe
{
private
volatile
Map<String,Object>
map
=
null;
public
void
useMap()
{
if
(map
==
null)
{
initMap();
}
//
read
the
map;
get(),
iterate,
...
}
private
synchronized
void
initMap()
{
if
(map
==
null)
{
Map<String,Object>
temp
=
new
HashMap<String,Object>();
//
populate
temp
with
initial
data
map
=
temp;
//
make
it
available
after
it’s
ready
}
}
}
8
9. Agenda
Introduction
Patterns & anti-patterns
Warm-up: “double-checked locking” on collections
Many readers, few writers
Many writers, few readers
Bonus: configuring a ThreadPoolExecutor
Closing...
9
10. Many readers, few writers
Use cases: change data only on demand (e.g.
configuration), ...
Implementation choices
1. Synchronized data structure
2. Concurrent collections (e.g. ConcurrentHashMap)
3. ReadWriteLock
4. “Copy-on-write”
10
11. Many readers, few writers
Example: using synchronization
class
Synchronized
{
private
final
List<String>
list
=
new
ArrayList<String>();
//
the
entire
iteration
must
be
synchronized
public
synchronized
void
iterateOnList()
{
for
(String
s:
list)
{
//
do
something
with
s
}
}
public
synchronized
void
add(String
value)
{
list.add(value);
}
}
11
12. Many readers, few writers
Example: using ReadWriteLock
class
UsingReadWriteLock
{
private
final
List<String>
list
=
new
ArrayList<String>();
private
final
ReadWriteLock
lock
=
new
ReentrantReadWriteLock();
public
void
iterateOnList()
{
lock.readLock().lock();
try
{
for
(String
s:
list)
{
//
do
something
with
s
}
}
finally
{
lock.readLock().unlock();
}
}
//
continued...
12
13. Many readers, few writers
Example: using ReadWriteLock
//
continued
public
void
add(String
value)
{
lock.writeLock().lock();
try
{
list.add(value);
}
finally
{
lock.writeLock().unlock();
}
}
}
13
14. Many readers, few writers
Copy-on-write
If writes are truly few and far between, and you want reads to
be as fast as possible, copy-on-write is an option
You copy and replace the entire data on every write
You eliminate synchronization on reads, and shift the burden
to writes
Writes usually become much more expensive
example: java.util.concurrent.CopyOnWriteArrayList
14
15. Many readers, few writers
Example: using copy-on-write
class
CopyOnWrite
{
private
volatile
List<String>
list
=
new
ArrayList<String>();
public
void
iterateOnList()
{
//
no
locking
needed
for
(String
s:
list)
{
//
do
something
with
s
}
}
public
synchronized
void
add(String
value)
{
//
need
mutual
exclusion
List<String>
copy
=
new
ArrayList<String>(list);
//
create
a
copy
copy.add(value);
list
=
copy;
}
}
15
16. Many readers, few writers
What’s wrong with this?
class
BadCopyOnWrite
{
private
volatile
List<String>
list
=
new
ArrayList<String>();
public
void
iterateOnList()
{
//
no
locking
needed
for
(int
i
=
0;
i
<
list.size();
i++)
{
String
s
=
list.get(i);
//
do
something
with
s
}
}
public
synchronized
void
add(String
value)
{
//
need
mutual
exclusion
List<String>
copy
=
new
ArrayList<String>(list);
//
create
a
copy
copy.add(value);
list
=
copy;
}
}
16
17. Many readers, few writers
Of course you can simply use CopyOnWriteArrayList!
class
CopyOnWrite2
{
private
final
List<String>
list
=
new
CopyOnWriteArrayList<String>();
public
void
iterateOnList()
{
//
no
locking
needed
for
(String
s:
list)
{
//
do
something
with
s
}
}
public
void
add(String
value)
{
list.add(value);
}
}
17
18. Many readers, few writers
Type Concurrency Staleness behavior
Updates CANNOT occur
Fully synchronized Not concurrent
during read
Reads concurrent; writes
May reflect SOME updates
ConcurrentHashMap can be concurrent; read-
during read
write can be concurrent
Reads concurrent; writes
Updates CANNOT occur
ReadWriteLock not concurrent; read-write
during read
not concurrent
Reads concurrent; writes
Reflects NO updates during
Copy-on-write not concurrent; read-write
read
concurrent
18
19. Many readers, few writers
For Maps, copy-on-write is less useful as
ConcurrentHashMap is usually good enough
ReadWriteLock is an option, but is less concurrent than
and performs more poorly than ConcurrentHashMap
Copy-on-write has the best read performance
19
20. Many readers, few writers
Copy-on-write: caveats
The write performance
The staleness behavior should be acceptable (it usually is)
The direct reference to the underlying data that is copied
should not escape the object
Stale data
Memory leaks
20
21. Many readers, few writers
What should we use?
If the (read) concurrency is low, synchronization is often good
enough
Choose concurrent collections (ConcurrentHashMap, etc.) if
applicable
Use copy-on-write if concurrent collections are not
applicable and write performance is not a concern
21
22. Many readers, few writers
How about copy-on-write on MULTIPLE variables?
22
23. Many readers, few writers
Multi-variable example: using synchronization
class
Synchronized
{
private
Map<String,String>
current
=
new
HashMap<String,String>();
private
Map<String,String>
previous
=
null;
public
synchronized
void
shift()
{
previous
=
current;
current
=
new
HashMap<String,String>();
}
public
synchronized
void
putValue(String
key,
String
value)
{
current.put(key,
value);
}
public
synchronized
void
getValue(String
key)
{
return
current.get(key);
}
}
23
24. Many readers, few writers
Copy-on-write on multiple variables
Use a container class with those variables
Do a volatile copy-and-replace with the container object
24
25. Many readers, few writers
Multi-variable example: use a container class
class
ShiftingWindow
{
final
Map<String,String>
current;
final
Map<String,String>
previous;
public
ShiftingWindow(Map<String,String>
c,
Map<String,String>
p)
{
current
=
c;
previous
=
p;
}
}
25
26. Many readers, few writers
Multi-variable example: use a container class
class
CopyOnWrite
{
private
volatile
ShiftingWindow
window
=
new
ShiftingWindow(new
ConcurrentHashMap<String,String>(),
null);
public
synchronized
void
shift()
{
//
copy
on
write
ShiftingWindow
newWindow
=
new
ShiftingWindow(new
ConcurrentHashMap<String,String>(),
window.current);
window
=
newWindow;
}
public
void
putValue(String
key,
String
value)
{
//
no
locking
window.current.put(key,
value);
}
public
void
getValue(String
key)
{
//
no
locking
return
window.current.get(key);
}
}
26
27. Agenda
Introduction
Patterns & anti-patterns
Warm-up: “double-checked locking” on collections
Many readers, few writers
Many writers, few readers
Bonus: configuring a ThreadPoolExecutor
Closing...
27
28. Many writers, few readers
Use cases: logging, counters, statistics, ...
Produce secondary data (e.g. URL counts) from primary
operations (serving URLs)
Many writers: all servlet threads will update the data
frequently
Few readers: the data will be read on demand (reporting) or
periodically
Impact on the primary operations must be minimized
28
29. Many writers, few readers
Implementation choices
1. Synchronized data structure
2. ConcurrentHashMap (for a map or set)
3. Asynchronous (background) processor
29
30. Many writers, few readers
1. Synchronized data structure
Not recommended
Can induce a hotly contended lock under high level of
concurrency, and turn into a scalability hot spot
2. ConcurrentHashMap
Normally the best solution
Scales well under high level of concurrency
3. Asynchronous (background) processor
Useful pattern if ConcurrentHashMap is not an option or
write operations are serial in nature
30
31. Many writers, few readers
Synchronized data structure
class
SynchronizedCounter
{
private
final
Map<String,Integer>
map
=
new
HashMap<String,Integer>();
public
synchronized
void
addCount(String
page)
{
Integer
value
=
map.get(page);
value
=
(value
==
null)
?
1
:
value+1;
map.put(page,
value);
}
public
synchronized
int
getCount(String
page)
{
Integer
value
=
map.get(page);
return
(value
==
null)
?
0
:
value;
}
}
31
32. Many writers, few readers
ConcurrentHashMap
class
ConcurrentHashMapCounter
{
private
final
ConcurrentMap<String,AtomicInteger>
map
=
new
ConcurrentHashMap<String,AtomicInteger>();
public
void
addCount(String
page)
{
AtomicInteger
value
=
map.get(page);
if
(value
==
null)
{
value
=
new
AtomicInteger(0);
AtomicInteger
old
=
map.putIfAbsent(page,
value);
if
(old
!=
null)
{
value
=
old;
}
}
value.incrementAndGet();
}
//
continued...
32
33. Many writers, few readers
ConcurrentHashMap
//
continued
public
int
getCount(String
page)
{
AtomicInteger
value
=
map.get(page);
return
(value
==
null)
?
0
:
value.get();
}
}
33
34. Many writers, few readers
Asynchronous (background) processor
A single background processor thread owns the data
Primary threads produce tasks for the background processor
Writes and reads are actually done on the background
processor thread
34
35. Many writers, few readers
Asynchronous (background) processor: benefits
Latency on the primary threads is minimized
Contention is greatly reduced: can yield much better
throughput than synchronization
Trivially thread safe: exploits safety via thread confinement
Example: logging to disk/console
35
36. Many writers, few readers
Asynchronous (background) processor: caveats
The data structure should not escape the background thread
The actual tasks should be thread-agnostic
Performs poorly against a more concurrent solution
Code becomes bit more complicated
You need to manage saturation: tasks may be produced faster
than they can be handled by the processor
36
37. Many writers, few readers
Asynchronous (background) processor
class
BackgroundCounter
{
//
background
thread
private
final
ExecutorService
executor
=
Executors.newSingleThreadExecutor();
//
map
is
exclusively
used
by
the
executor
thread
private
final
Map<String,Integer>
map
=
new
HashMap<String,Integer>();
public
void
addCount(String
page)
{
executor.execute(new
AddTask(page));
}
public
int
getCount(String
page)
{
Future<Integer>
future
=
executor.submit(new
GetTask(page));
return
future.get();
//
exception
handling
omitted
}
//
continued...
37
38. Many writers, few readers
Asynchronous (background) processor
//
continued
private
class
AddTask
implements
Runnable
{
private
final
String
page;
AddTask(String
page)
{
this.page
=
page;
}
public
void
run()
{
Integer
value
=
map.get(page);
value
=
(value
==
null)
?
1
:
value+1;
map.put(page,
value);
}
}
//
continued...
38
39. Many writers, few readers
Asynchronous (background) processor
//
continued
private
class
GetTask
implements
Callable<Integer>
{
private
final
String
page;
GetTask(String
page)
{
this.key
=
page;
}
public
Integer
call()
{
Integer
value
=
map.get(page);
return
(value
==
null)
?
0
:
value;
}
}
}
39
40. Agenda
Introduction
Patterns & anti-patterns
Warm-up: “double-checked locking” on collections
Many readers, few writers
Many writers, few readers
Bonus: configuring a ThreadPoolExecutor
Closing...
40
41. Configuring a ThreadPoolExecutor
Right configuration that fits your use case and demand is
extremely important
Badly configured ThreadPoolExecutors cause exceptions
and performance issues
RejectedExecutionExceptions anyone?
41
42. Configuring a ThreadPoolExecutor
Simple rules for ThreadPoolExecutor behavior
When a task is submitted:
1. If the core size has not been reached, a new thread is always
created
2. If the core size is reached, the task is queued
3. If the core size is reached and the queue becomes full, a new
thread is created until the max size is reached
4. If the max size is reached and the queue is full, the rejected
execution policy kicks in
42
43. Configuring a ThreadPoolExecutor
Importance of core size
ThreadPoolExecutor changes behavior dramatically around
the core size
Below core size, threads are always created even if there are
idle threads
Above core size, the preferred behavior shifts to queuing
Core size should be big enough to accommodate the
anticipated average task throughput demand
43
44. Configuring a ThreadPoolExecutor
Thread pool size and queue size are competing parameters
Queuing increases latency but conserves resource
A queued task in general consumes less resource than an
active task
Reduce latency Conserve resource
Larger pool size Smaller pool size
Smaller queue Larger queue
44
45. Closing...
Power of static analysis
Whenever we find an issue, we try to turn it into a static
analysis rule
FindBugs already has many useful thread-safety rules
Intent is the most difficult part with thread-safety analysis:
annotations help
Continued training helps as well
45
48. TPE: Cancelling tasks
Cancelling tasks: more complicated than you think
Cancelling tasks is your job
Timing out from Future.get() does NOT cancel the task by
itself
Some TPE methods cancel outstanding tasks for you:
invokeAll() with timeout, invokeAny()
Cancelling tasks uses interruption: you should write your task
to respond to cancellation promptly (i.e. “interruptible”)
48
50. TPE & UncaughtExceptionHandler
Multi-threaded test with vanilla thread
class
TestWithThreads
extends
TestCase
{
@Test
public
void
test()
{
MyHandler
h
=
new
MyHandler();
Thread
th
=
new
Thread(someRunnable);
th.setUncaughtExceptionHandler(h);
th.start();
th.join();
//
check
MyHandler
for
any
exception
on
thread
th
}
private
static
class
MyHandler
implements
UncaughtExceptionHandler
{
public
void
uncaughtException(Thread
t,
Throwable
e)
{
//
store
the
exception
}
}
}
50
51. TPE & UncaughtExceptionHandler
Multi-threaded test with TPE stops working: why?
class
BrokenTestWithExecutor
extends
TestCase
{
private
ExecutorService
executor
=
Executors.newSingleThreadExecutor();
@Test
public
void
test()
{
MyHandler
h
=
new
MyHandler();
Thread.setDefaultUncaughtExceptionHandler(h);
executor.submit(someRunnable).get();
//
check
MyHandler
for
any
exception
on
thread
th
}
private
static
class
MyHandler
implements
UncaughtExceptionHandler
{
public
void
uncaughtException(Thread
t,
Throwable
e)
{
//
store
the
exception
}
}
}
51
52. TPE & UncaughtExceptionHandler
Remember what UncaughtExceptionHandlers are for!
UncaughtExceptionHandlers are invoked only if the thread is
being terminated due to an uncaught exception
Some (not all) TPE methods catch and handle all exceptions
ThreadPoolExecutor
execute(): triggers UncaughtExceptionHandlers
submit(): does not trigger them
ScheduledThreadPoolExecutor: does not trigger them
52
53. TPE & UncaughtExceptionHandler
Simply don’t rely on UncaughtExceptionHandlers with TPE
Using Future and ExecutionException is the right way with
TPE
53
54. TPE & UncaughtExceptionHandler
Multi-threaded test with TPE: correct
class
CorrectTestWithExecutor
extends
TestCase
{
private
ExecutorService
executor
=
Executors.newSingleThreadExecutor();
@Test
public
void
test()
{
try
{
executor.submit(someRunnable).get();
}
catch
(ExecutionException
e)
{
//
its
cause
is
the
original
exception
Throwable
cause
=
e.getCause();
//
assert
failure
}
catch
(InterruptedException
e2)
{
...
}
}
}
54