w13 Concurrency Curs
w13 Concurrency Curs
Concurrency
Threads
Threads
• A multi-threaded software contains two or more parts that can run concurrently and each
part can handle a different task at the same time making optimal use of available resources
• Especially useful when your computer has multiple CPUs (4-8-16..)
Process vs Thread
Process:
- started by OS (when launching an application..)
- typically independent, each has separate memory space
- has considerably more state info (open files, etc)
- interact only through system IPC (expensive, limited)
- hard/expensive to create new one (duplicate parent)
Thread:
- subset of a process (cannot exist without), at least one
- multiple threads of a process share process state, some
shared memory, etc
- each also has its own address space (stack)
- can easily communicate / interact with other threads
- smaller memory overhead and context-switching cost
- easy to create (from other threads)
Java threads
- A Java application is started by running “java.exe” with some params, like main class...
- Any executing java code has a current thread is running on (by), represented by an
instance of the Thread class
Steps:
• Create a class implementing Runnable interface, and put all your business logic
code in the run() method (required by the interface)
• Start the new thread by calling its start() method - this will start running the run()
method of your runnable in a new execution thread
Creating threads – by implementing Runnable (1)
@Override
public void run() {
System.out.println(name + ": Start running...");
try {
for (int i = 1; i <= 3; i++) {
System.out.println(name + ": " + i);
Thread.sleep(50);
}
System.out.println(name + ": ...finished");
} catch (InterruptedException e) {
System.out.println(name + ": thread interrupted");
}
}
}
Creating threads – by implementing Runnable (2)
Steps:
• Create a custom class extending the Thread class, and override its run() method,
putting all your business logic there
• Create an instance of this custom Thread class and start it by calling its start()
method, which will run the run() method in a new execution thread
Note: you must call the start() method on the thread instance to start a new thread;
avoid the common mistake of calling directly the run() method, as this will just run
that code in the current thread! (not a new one)
Creating threads – by extending Thread class (1)
@Override
public void run() {
System.out.println(getName() + ": Running thread...");
try {
for (int i = 1; i <= 3; i++) {
System.out.println(getName() + ": " + i);
Thread.sleep(50);
}
System.out.println(getName() + ": ...finished");
} catch (InterruptedException e) {
System.out.println(getName() + ": Thread interrupted");
}
}
}
Creating threads – by extending Thread class (2)
//start them
t1.start();
t2.start();
}
}
Concurrent threads
- code of a thread may create and then start other new threads,
with “new Thread(..)” and then calling .start() on them
• No problems running multiple threads concurrently (as they are normally independent,
have own memory space, own slice of time on CPU) ...
• … until they start accessing shared resources (read+write memory/objects, files, etc)
○ they start to interfere and produce unpredictable results
Example:
- multiple threads trying to write to the same file may corrupt the data because one of the
threads can override data written by the other
- multiple threads updating same variable may overwrite each other’s changes
• “critical section” = a section of code where multiple threads access some shared resources, in an
unsafe way so that the results are unpredictable / depend on the timing of each thread
○ “race condition” - name of such a situation of threads ‘racing’ to access same resources
http://tutorials.jenkov.com/java-concurrency/race-conditions-and-critical-sections.html
Shared memory
How it works:
• each Java object is associated with a monitor, which a thread can lock/unlock
• only one thread at a time may hold a lock on a specific monitor!
synchronized
- marks that a block of code is protected by a lock / can be accessed by only one thread at a time!
- other threads which want to access a block (same or other) synchronized on same lock will
be blocked until first thread exists the synchronized block (and releases the lock)
- can be applied to:
- methods - instance or static -> the lock object is implicit, either “this” (for instance methods)
or the class definition itself (for static)
- blocks of code - instance or static -> the lock object needs to be specified explicitly
class MyLogger {
class Counter {
long count = 0;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
counter.add(1);
}
}
}
Deadlocks
Happens when:
- different threads want to lock multiple resources at
the same time
- if some of them obtain only some of the locks, but
others obtain the rest, they may end in a deadlock -
none can proceed, none gives up already take
locks, so they all remain blocked forever
Thread.sleep(1000);
Atomic variables are faster, easier to work with, less risk of “forgetting” to lock
Thread.sleep(1000);
System.out.println(atomicCounter.get()); //-> 1000000 (as expected)
}
Concurrent Collections
Concurrent Collections
for (int i = 0; i < 100; i++) //each adds 100 values to same list
list.add(i);
}).start();
}
System.out.println("List size: " + list.size() + ", expected: 10000");
What do you think will the list contain after executing this code?
Concurrent Collections
Concurrent collections:
● special collections that can be used safely by multiple threads
● they do have a performance impact, but lower than manually using locks
● java.util.concurrent package (see summary here)
Examples:
● ConcurrentHashMap
● CopyOnWriteArrayList
● CopyOnWriteArraySet
Concurrent Collections
Important:
● All methods in concurrent collections are thread safe (individually!)
● But multiple method calls are not atomic!
if(!concurrentMap.containsKey(5)) {
//← another thread may have changed the map exactly here!
concurrentMap.put(5, "somevalue");
}
The block is not atomic: another thread might have added a value at precisely the
time between the call to .containsKey() and the call to .put()
Concurrent Collections
Solution:
look for single operations that combine multiple basic operation in the way
you need them, to run them an atomic way.
- methods like: putIfAbsent(), computeIfPresent(),...
concurrentMap.putIfAbsent(5, "somevalue");
We want to process the produced data in parallel - using multiple consumer threads.
Possible solution:
● Create a thread pool for processing
● Send data from the first set of threads (or thread pool) to the other set of
“worker” threads (pool)
Concurrent Queues
java.util.concurrent.ConcurrentLinkedQueue
● Simplest option
● Unbound: cannot control how much the queue can grow
● Usable when the consumers are guaranteed* to be faster than the producers,
otherwise might grow indefinitely!
java.util.concurrent.ArrayBlockingQueue
● Backed by a fixed array
● Once it reaches the maximum size, producers are blocked until some space
becomes available again
java.util.concurrent.DelayQueue
● Elements can only be consumed after a certain delay
java.util.concurrent.TransferQueue
● Producers may wait until the element is consumed
java.util.concurrent.PriorityBlockingQueue
● Each element can have a priority
● Highest priority elements are consumed first
● https://beginnersbook.com/2013/03/java-threads/
● https://beginnersbook.com/2015/01/what-is-the-difference-between-a-process-an
d-a-thread-in-java/
● https://www.baeldung.com/java-thread-lifecycle
● http://tutorials.jenkov.com/java-concurrency/index.html
● https://beginnersbook.com/2013/03/multithreading-in-java/
● https://www.ibm.com/developerworks/java/tutorials/j-threads/j-threads.html
● https://dzone.com/articles/producer-consumer-pattern
● https://www.codejava.net/java-core/collections/java-producer-consumer-example
s-using-blockingqueue