Java Multithreading
Java Multithreading
388down
vote
non-updated value.
To answer your question: Yes, I use a volatile variable to control whether
some code continues a loop. The loop tests the volatile value and continues if
it is true. The condition can be set to false by calling a "stop" method. The loop
sees false and terminates when it tests the value after the stop method
completes execution.
The book "Java Concurrency in Practice," which I highly recommend, gives a
good explanation of volatile. This book is written by the same person who
wrote the IBM article that is referenced in the question (in fact, he cites his
book at the bottom of that article). My use of volatile is what his article calls
the "pattern 1 status flag."
If you want to learn more about how volatile works under the hood, read up
on the Java memory model. If you want to go beyond that level, check out a
good computer architecture book likeHennessy & Patterson and read about
cache coherence and cache consistency.
accepted
92down
vote
-
the volatile modifier guarantees that any thread that reads a field will see
the most recently written value. - Josh Bloch
If you are thinking about using volatile, read up on the
package java.util.concurrent which deals with atomic behaviour.
if one thread aquires the lock for Worker object & enters stageOne() the
other thread will have to wait to aquire lock to be able to run stageTwo()!!!
notice that the 2 methods are operating on different data: stageOne() on
list1, stageTwo() on list2
ideally we want to prohibit the threads to run the same method at the
same time, but let them run different methods (t1 stageOne(), t2
stageTwo()) at the same time
one way : ReentrantLock class
solution : create 2 locks for the 2 methods, use synchronized blocks
dont lock on the lists ! Declare separate lock objects to avoid confusion !
list1.add(random.nextInt(100));
}
public void stageTwo(){
synchronized(lock2){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list2.add(random.nextInt(100));
}
}
running time decreases like this, it takes 50% less time (2 ms) as opposed
to the previous synchronized declared methods (4 ms)
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
5. Thread Pools
- a thread pool = having a number of workers in a factory and you have a
load of tasks you want them to get through(ex. 5 tasks)
- when worker thread finishes processing a task, we want it to start
processing another
ExecutorService runs its own managerial thread that manages the worker
threads
submit to executorService the tasks you want handled by the worker
threads:
Processor class describes a task (by implementing Runnable)
//Runnable is a task/job
class Processor implements Runnable{
private int id;
public Processor(int id){
this.id = id ;
}
public void run() {
System.out.println("Starting: " + id);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Finished: " + id);
}
}
}
}
} catch (InterruptedException e) {
}
System.out.println("All tasks completed.");
output :
All tasks
Starting:
Starting:
Finished:
Finished:
Starting:
Starting:
Finished:
Finished:
Starting:
Finished:
All tasks
submitted.
0
1
0
1
2
3
3
2
4
4
completed.
6. Countdown Latches
- there are fortunately many classes in Java that are threadsafe, one of
them is a CountDownLatch, basically a counter that counts down and can
be decremented in different places in the code .
- code :
class Processor implements Runnable{
private CountDownLatch latch;
public Processor(CountDownLatch latch){
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();//latch counts down
}
}
public class App {
public static void main(String[] args) {
//one or more threads wait for the latch to count down from 5 time
units
CountDownLatch latch = new CountDownLatch(5);
ExecutorService executor = Executors.newFixedThreadPool(7);
//7 worker threads
for(int i = 0 ; i < 5 ; i++)
}
output : Started.
Started.
Started.
Started.
Started.
Completed.
7. Producer-Consumer
-
e.printStackTrace();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
private static void producer() throws InterruptedException{
Random random = new Random();
while(true){
//suppose the queue is full, put() method
//will patiently wait until items are removed from the queue
queue.put(random.nextInt(100));
}
}
private static void consumer() throws InterruptedException {
Random random = new Random();
while(true){
Thread.sleep(100);//takes time to process item
if(random.nextInt(10) == 0){
Integer value = queue.take(); // if there's nothing in
the queue it waits without consuming a lot
// of resources
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
10.
import
import
import
import
Re-entrant Locks
java.util.Scanner;
java.util.concurrent.locks.Condition;
java.util.concurrent.locks.Lock;
java.util.concurrent.locks.ReentrantLock;
increment();
}finally {// in case code throws an exception lock shouldn't
remain locked
lock.unlock();
}
public void secondThread() throws InterruptedException {
Thread.sleep(1000);
lock.lock();
increment();
}finally {
lock.unlock();
}
11.
Deadlock
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Runner {
private Account acc1 = new Account();
private Account acc2 = new Account();
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
gotFirstLock = firstLock.tryLock();
// Acquires the lock if it is not held by another
//thread and
// returns immediately with the value true, setting //
the lock
// hold count to one.
gotSecondLock = secondLock.tryLock();
} finally {
if (gotFirstLock && gotSecondLock) {
// if both locks can be acquired
return; // return from while(true) & //
//acquireLocks method,our goal was accomplished!
}
if (gotFirstLock) {
// if just the first lock acquired with
// tryLock() earlier
firstLock.unlock(); // unlock it to give other
threads the chance to lock it
// meanwhile this while(true) runs until
//both //locks can be acquired!!!
}
if (gotSecondLock) {// if just the second lock was
//acquired with tryLock() earlier
secondLock.unlock(); // unlock it to give other
threads the chance to lock it
// meanwhile this while(true) runs until
both //locks can be acquired!!!
}
}
// Locks not acquired so sleep for 1 ms
Thread.sleep(1);
}
acquireLocks(lock1, lock2);
try {
exception we
}
}
12.
-
Semaphores
A counting semaphore. Conceptually, a semaphore maintains a set of
permits.
Each acquire() blocks if necessary until a permit is available, and then
takes it.
Each release() adds a permit, potentially releasing a blocking acquirer.
However, no actual permit objects are used; the Semaphore just keeps a
count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can
access some (physical or logical) resource.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class App {
//
//
//
//
//
}
import java.util.concurrent.Semaphore;
public class Connection {
//this is a Singleton
private static Connection instance = new Connection();
//limit no. of connections any given time
//true param : to ensure fairness, you don;t want it to let a thread
hang in the
//background while other threads are being serviced
//fairness: which ever thread calls aquire first, gets a permit first
//(false as param.-> performance benefits)
Semaphore sem = new Semaphore(10, true);
private int connections = 0;
private Connection() {
}
//there's only one connection at a given time
public static Connection getInstance() {
return instance;
}
// if Thread.sleep were to throw an exception sem.release() would never
be calles
//renamed connect() to doConnect and this new connect() handles the
prev. named possibility
public void connect(){
try {
sem.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try{
doConnect();
}
finally{
sem.release();
}
13.
-
14.
import java.util.Random;
public class App {
public static void main(String[] args) throws InterruptedException {
System.out.println("Starting.");
Thread t1 = new Thread(new Runnable(){
public void run() {
Random ran = new Random();
for(int i = 0 ; i < 1E8; i++){ //1E8 = 1 * 10^8
//to check if your thread has been interrupted
/*
if (Thread.currentThread().isInterrupted()){
System.out.println("Interrupted!");
break;
}
*/
try{
Thread.sleep(1);
} catch(InterruptedException e){
System.out.println("Interrupted!");
break;
}
}
Math.sin(ran.nextDouble());
}});
t1.start();
Thread.sleep(500);
//doesn't stop thread, sets a flag telling thread that
it is being interrupted
t1.interrupt();
//if you want to know if thread has been interrupted
you have to quiz the thread
t1.join();
System.out.println("Finished.");
}
}
15.
-