0% found this document useful (0 votes)
72 views23 pages

Date

The document discusses several topics related to threading and synchronization in Java: 1. It provides examples of using synchronized blocks and methods to demonstrate thread synchronization. 2. It discusses the built-in annotations @Override, @Deprecated, and @SuppressWarnings and provides code examples. 3. It explains the wait(), notify(), and notifyAll() methods and how they can be used for inter-thread communication through an example.

Uploaded by

Vds Krishna
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views23 pages

Date

The document discusses several topics related to threading and synchronization in Java: 1. It provides examples of using synchronized blocks and methods to demonstrate thread synchronization. 2. It discusses the built-in annotations @Override, @Deprecated, and @SuppressWarnings and provides code examples. 3. It explains the wait(), notify(), and notifyAll() methods and how they can be used for inter-thread communication through an example.

Uploaded by

Vds Krishna
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 23

Date : 11 October, 2018

Thread Synchronization
1. Write a Java program to demonstrate “synchronized” block
2. Write a Java program to demonstrate “synchronized” method
3. Write a Java program to demonstrate to simulate
concurrency(inthread communication) in java ( use wait(),notify()
methods)
4. Develop an application to simulate Producer Consumer problem using
multithreading
5. Write a simulation program for the fruit market. The farmer will be
able to produce different types of fruits (apple, orange, grape, and
watermelon), and put them in the market to sell. The market has
limited capacity and farmers have to stand in a queue if the
capacity is exceeded to sell their fruits. Consumers can come to
the market any time and purchase their desired fruits; and if the
fruits they want to buy runs out, they are willing to wait until the supply
of that kind is ready. (Hint: implementing this market will encounter the
producer and consumer problem, and it probably needs multiple buffers for
different kinds of fruits).

Annotations(Built-in annotations)
1. Write a Java program to demonstrate ‘@override’ annotation
@Override – When we want to override a method of Superclass, we should use this
annotation to inform compiler that we are overriding a method. So when superclass
method is removed or changed, compiler will show error message
2. Write a Java program to demonstrate ‘@Deprecated’ annotation
when we want the compiler to know that a method is deprecated, we should
use this annotation. Java recommends that in javadoc, we should provide
information for why this method is deprecated and what is the
alternative to use

3. Write a Java program to demonstrate ‘@SuppressWarnings’


annotation
just to tell compiler to ignore specific warnings they produce, for
example using raw types in java generics. It’s retention policy is

SOURCE and it gets discarded by compiler.


Annotation Examples
1)@override example
class ParentClass
{
public void displayMethod(String msg){
System.out.println(msg);
}
}
class SubClass extends ParentClass
{
@Override
public void displayMethod(String msg){
System.out.println("Message is: "+ msg);
}
public static void main(String args[]){
SubClass obj = new SubClass();
obj.displayMethod("Hey!!");
}
}
2)@Deprecated example
public class MyDeprecatedExmp {

/**
* @deprecated
* reason for why it was deprecated
*/
@Deprecated
public void showDeprecatedMessage(){
System.out.println("This method is marked as deprecated");
}

public static void main(String a[]){

MyDeprecatedExmp mde = new MyDeprecatedExmp();


mde.showDeprecatedMessage();
}
}
The @Deprecated annotation will be used to inform the compiler to generate a warning
whenever a program uses a method, class, or field with the @Deprecated annotation. It is good to
document the reason with Javadoc @deprecated tag. Make a note of case difference with
@Deprecated and @deprecated. @deprecated is for documentation purpose.
3)@SupressWarnings
public class MyDeprecatedExmp {

     

    @Deprecated

    public void showDeprecatedMessage(){


        System.out.println("This method is marked as deprecated");

    }

     

    @SuppressWarnings("deprecation")

    public static void main(String a[]){

         

        MyDeprecatedExmp mde = new MyDeprecatedExmp();

        mde.showDeprecatedMessage();

    }

Incase if you don't want to get any warnings from compiler for the known things, then you can
use @SuppressWarnings annotation. For example, you are calling deprecated method, and you
know that it is deprecated, to avoid compiler warnings, user @SuppressWarnings annotation.
Interthread Communication

wait, notify and notifyAll in Java


The current thread which invokes these methods on any object should have the object monitor
else it throws java.lang.IllegalMonitorStateException exception.

wait

Object wait methods has three variance, one which waits indefinitely for any other thread to call
notify or notifyAll method on the object to wake up the current thread. Other two variances puts
the current thread in wait for specific amount of time before they wake up.

notify

notify method wakes up only one thread waiting on the object and that thread starts execution.
So if there are multiple threads waiting for an object, this method will wake up only one of them.
The choice of the thread to wake depends on the OS implementation of thread management.

notifyAll

notifyAll method wakes up all the threads waiting on the object, although which one will process
first depends on the OS implementation.

These methods can be used to implement producer consumer problem where consumer threads
are waiting for the objects in Queue and producer threads put object in queue and notify the
waiting threads.
1. synchronized keyword is used for exclusive accessing.
2. To make a method synchronized, simply add the synchronized keyword to its declaration.
Then no two invocations of synchronized methods on the same object can interleave with
each other.
3. Synchronized statements must specify the object that provides the intrinsic lock. When
synchronized(this) is used, you have to avoid to synchronizing invocations of other
objects' methods.
4. wait() tells the calling thread to give up the monitor and go to sleep until some other
thread enters the same monitor and calls notify( ).
5. notify() wakes up the first thread that called wait() on the same object.

Example:
Message.java

A java class on which threads will work and call wait and notify methods.

public class Message {


private String msg;

public Message(String str){


this.msg=str;
}

public String getMsg() {


return msg;
}

public void setMsg(String str) {


this.msg=str;
}

Waiter.java

A class that will wait for other threads to invoke notify methods to complete it’s
processing. Notice that Waiter thread is owning monitor on Message object using
synchronized block.
public class Waiter implements Runnable{

private Message msg;

public Waiter(Message m){


this.msg=m;
}

@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at
time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at
time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}

Notifier.java

A class that will process on Message object and then invoke notify method to wake up threads
waiting for Message object. Notice that synchronized block is used to own the monitor of
Message object.

public class Notifier implements Runnable


{
private Message msg;

public Notifier(Message msg) {


this.msg = msg;
}

@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}

InterThreadCommunicationDemo
Test class that will create multiple threads of Waiter and Notifier and start them.

public class InterThreadCommunicationDemo {

public static void main(String[] args) {


// TODO Auto-generated method stub
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();

Waiter waiter1 = new Waiter(msg);


new Thread(waiter1, "waiter1").start();

Notifier notifier = new Notifier(msg);


new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");

Producer Consumer /Bounded Buffer Problem(Inthread communication)


Inter thread communication

Producer Consumer/Bounded Buffer Problem.

Producer Consumer Problem is well-known example of multi-thread synchronization problem.


It is described as synchronization problem over a fixed size data buffer implemented as queue
being modified by two or more different processes referred as producers and consumers. For a
data buffer, we can have multiple number of producers and consumers. Producers task is to keep
generating data and place it into buffer while Consumers task is to keep consuming data from
buffer. Problem is to ensure that Producers do not add data into buffer if its full and Consumer
do not consumer data if buffer is empty.
For resolving above problem, Producer and Consumer should behave as below.

Producer

1. Check if Buffer is full or not. If full, then wait() for buffer items to get consumed.

2. Generate data and put it into Buffer.

3. Notify Consumer that Data has been placed into Buffer.

4. Repeat step 1-3

Consumer

1. Check if Buffer has items. If empty, then wait() for buffer to get filled.

2. Consume data from Buffer.

3. Notify Producer that Data has been consumed from Buffer

4. Repear step 1-3

Synchronized Instance Methods


A synchronized instance method in Java is synchronized on the instance (object) owning the
method. Thus, each instance has its synchronized methods synchronized on a different object:
the owning instance. Only one thread can execute inside a synchronized instance method.

Example #1
class Q
{
int n;
boolean valueSet=false;
synchronized int get()
{
if(!valueSet)
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
System.out.println("Got:"+n);
valueSet=false;
notify();
return n;
}
synchronized void put(int n)
{
if(valueSet)
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
this.n=n;
valueSet=true;
System.out.println("Put:"+n);
notify();
}
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q=q;
new Thread(this,"Producer").start();
}
public void run()
{
int i=0;
while(true)
{
q.put(i++);
}
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q=q;
new Thread(this,"Consumer").start();
}
public void run()
{
while(true)
{
q.get();
}
}
}
class ProdConsDemo
{
public static void main(String[] args)
{
Q q=new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-c to stop");
}
} class Q
{
int n;
boolean valueSet=false;
synchronized int get()
{
if(!valueSet)
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
System.out.println("Got:"+n);
valueSet=false;
notify();
return n;
}
synchronized void put(int n)
{
if(valueSet)
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
this.n=n;
valueSet=true;
System.out.println("Put:"+n);
notify();
}
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q=q;
new Thread(this,"Producer").start();
}
public void run()
{
int i=0;
while(true)
{
q.put(i++);
}
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q=q;
new Thread(this,"Consumer").start();
}
public void run()
{
while(true)
{
q.get();
}
}
}
class ProdCons
{
public static void main(String[] args)
{
Q q=new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-c to stop");
}
}
Example #2

import java.util.*;
class Buffer {
private int data;
private boolean empty;

public Buffer()
{
this.empty = true;
}

public synchronized void produce(int newData) {


while (!this.empty) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.data = newData;
this.empty = false;
this.notify();
System.out.println("Producer put...:" + newData);
}

public synchronized int consume() {


while (this.empty) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.empty = true;
this.notify();
System.out.println("Consumer get...:" + data);
return data;
}
}
/*Producer */
class Producer extends Thread {
private Buffer buffer;

public Producer(Buffer buffer) {


this.buffer = buffer;
}

public void run() {


Random rand = new Random();
while (true) {
int n = rand.nextInt();
buffer.produce(n);
}
}
}

/*Consumer */
class Consumer extends Thread {
private Buffer buffer;

public Consumer(Buffer buffer) {


this.buffer = buffer;
}

public void run() {


int data;
while (true) {
data = buffer.consume();
}
}
}

public class ProducerConsumer


{
public static void main(String[] args)
{
Buffer buffer = new Buffer();
Producer p = new Producer(buffer);
Consumer c = new Consumer(buffer);

p.start();
c.start();
}
}

Example #2
class BankQueue {
int nextToGive=0, nextToServe=0;
synchronized int nextNumberToCustomer() {
notify();
return ++nextToGive;
}
synchronized int nextToServe() throws InterruptedException{
if (!(nextToServe<nextToGive)){
System.out.println("Waiting");
wait();
}
return ++nextToServe;
}
}

class Consumer implements Runnable{


BankQueue queue;
Consumer(BankQueue queue) { this.queue=queue;}
public void run() {
try {
while (true) {
int n=queue.nextToServe();
System.console().format("Serving customer no: %d\n",n);
}
} catch(InterruptedException e) {}
}
}
class Producer implements Runnable{
BankQueue queue;
Producer(BankQueue queue) { this.queue=queue;}
public void run() {
while (true) {
int n=queue.nextNumberToCustomer();
System.console().format("New customer no: %d\n",n);
}
}
}
class ProducerConsumerBank {
public static void main(String[] args) {
int numConsumers=10, numProducers=2;
BankQueue theQueue=new BankQueue();
for(int i=0;i<numConsumers;i++)
new Thread(new Consumer(theQueue)).start();
for(int i=0;i<numProducers;i++)
new Thread(new Producer(theQueue)).start();
}
}
Java Annotations
Java Annotations allow us to add metadata information into our source code,
although they are not a part of the program itself. Annotations were added to the
java from JDK 5. Annotation has no direct effect on the operation of the code they
annotate (i.e. it does not affect the execution of the program).

What’s the use of Annotations?


1) Instructions to the compiler: There are three built-in annotations available in Java
(@Deprecated, @Override & @SuppressWarnings) that can be used for giving certain
instructions to the compiler. For example the @override annotation is used for instructing
compiler that the annotated method is overriding the method. More about these built-in
annotations with example is discussed in the next sections of this article.

2) Compile-time instructors: Annotations can provide compile-time instructions to the compiler


that can be further used by sofware build tools for generating code, XML files etc.

3) Runtime instructions: We can define annotations to be available at runtime which we can access
using java reflection and can be used to give instructions to the program at runtime.

Annotations basics
An annotation always starts with the symbol @ followed by the annotation name. The symbol @
indicates to the compiler that this is an annotation.

For e.g. @Override


Here @ symbol represents that this is an annotation and the Override is the name of this
annotation.

Where we can use annotations?


Annotations can be applied to the classes, interfaces, methods and fields. For example the below
annotation is being applied to the method.

@Override
void myMethod() {
//Do something
}

What this annotation is exactly doing here is explained in the next section but to be brief it is
instructing compiler that myMethod() is a overriding method which is overriding the method
(myMethod()) of super class.
Built-in Annotations in Java
Java has three built-in annotations:

 @Override
 @Deprecated

 @SuppressWarnings

1) @Override:

While overriding a method in the child class, we should use this annotation to mark that method.
This makes code readable and avoid maintenance issues, such as: while changing the method
signature of parent class, you must change the signature in child classes (where this annotation is
being used) otherwise compiler would throw compilation error. This is difficult to trace when
you haven’t used this annotation.

Example:

public class MyParentClass {

public void justaMethod() {


System.out.println("Parent class method");
}
}

public class MyChildClass extends MyParentClass {

@Override
public void justaMethod() {
System.out.println("Child class method");
}
}

I believe the example is self explanatory. To read more about this annotation, refer this article:
@Override built-in annotation.

2) @Deprecated

@Deprecated annotation indicates that the marked element (class, method or field) is deprecated
and should no longer be used. The compiler generates a warning whenever a program uses a
method, class, or field that has already been marked with the @Deprecated annotation. When an
element is deprecated, it should also be documented using the Javadoc @deprecated tag, as
shown in the following example. Make a note of case difference with @Deprecated and
@deprecated. @deprecated is used for documentation purpose.

Example:
/**
* @deprecated
* reason for why it was deprecated
*/
@Deprecated
public void anyMethodHere(){
// Do something
}

Now, whenever any program would use this method, the compiler would generate a warning. To
read more about this annotation, refer this article: Java – @Deprecated annotation.

3) @SuppressWarnings

This annotation instructs compiler to ignore specific warnings. For example in the below code, I
am calling a deprecated method (lets assume that the method deprecatedMethod() is marked with
@Deprecated annotation) so the compiler should generate a warning, however I am using
@@SuppressWarnings annotation that would suppress that deprecation warning.

@SuppressWarnings("deprecation")
void myMethod() {
myObject.deprecatedMethod();
}

You might also like