What is Producer - Consumer Problem?
In Simple term we can say, when two Process trying to access same(commonly shared) resource at the same time and one failed to do its operation because another process is using that resource.
In this article we'll generate the Producer - Consumer problem using threads that are trying to access common resource. One thread that is adding/removing records to the
List<Integer> and another thread trying to print the records of
List<Integer> one-by-one.
Source Code(Problem Generation)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ProducerConsumerExample {
/* Create common List of Integer. */
private static List<Integer> listIntegers = new ArrayList<Integer>();
public static void main(String[] args) {
/* Start Producer Thread */
new ProducerThread().start();
/* Start Consumer Thread */
new ConsumerThread().start();
}
/* Producer thread that will add/remove records to `listIntegers` */
public static class ProducerThread extends Thread{
@Override
public void run() {
int index = 0;
while(true){
try {
/* Put thread in sleep for `1 milliseconds` */
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
if(listIntegers.size() < 100){
/* Add record to List */
listIntegers.add(index);
/* Print the records of List */
System.out.println("Producer Thread: \n" + listIntegers);
index++;
}else{
/* Remove 1st element from List */
listIntegers.remove(0);
}
}
}
}
/* Consumer thread that will iterate records of `listIntegers` */
public static class ConsumerThread extends Thread{
@Override
public void run() {
while(true){
try {
/* Put thread in sleep for `1 milliseconds` */
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Consumer Thread iterator list: ");
/* Get iterator of List */
Iterator<Integer> iterator = listIntegers.iterator();
/* Iterate List until last element */
while(iterator.hasNext()){
/* Print the element */
System.out.print(iterator.next() + ", ");
if(!iterator.hasNext()){
System.out.println("");
}
}
}
}
}
}
When you run the above program it'll throw an exception
java.util.ConcurrentModificationException as shown in following output.
Note: When you execute this program in your system you won't get same output. It depends upon the execution of Thread in your system.
Output
As you can see clearly portion marked within
=. Consumer Thread Iterating the
List<Integer> and printed
0 and at the same time Producer Thread added record and Consumer Thread thrown an exception.
/* Removed few lines from output. It printed data of list from 0 to 3 */
Producer Thread:
[0, 1, 2, 3, 4]
Consumer Thread iterator list:
0, 1, 2, 3, 4,
Producer Thread:
[0, 1, 2, 3, 4, 5]
==========================================
Consumer Thread iterator list:
0, Producer Thread:
[0, 1, 2, 3, 4, 5, 6]
Exception in thread "Thread-1" Producer Thread:
[0, 1, 2, 3, 4, 5, 6, 7]
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at javaQuery.thread.ProducerConsumerExample$ConsumerThread.run(ProducerConsumerExample.java:51)
==========================================
Solution
We can solve this problem using
synchronized keyword.
synchronized takes care for accessing
List<Integer>, while one thread is accessing the
List<Integer> another thread has to wait until first thread finishes its work.
Source Code(Solving Problem)
Following program will not give
java.util.ConcurrentModificationException exception.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ProducerConsumerExample {
/* Create common List of Integer. */
private static List<Integer> listIntegers = new ArrayList<Integer>();
public static void main(String[] args) {
/* Start Producer Thread */
new ProducerThread().start();
/* Start Consumer Thread */
new ConsumerThread().start();
}
/* Producer thread that will add/remove records to `listIntegers` */
public static class ProducerThread extends Thread{
@Override
public void run() {
int index = 0;
while(true){
try {
/* Put thread in sleep for `1 milliseconds` */
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
/* synchronized block */
synchronized (listIntegers) {
if(listIntegers.size() < 100){
/* Add record to List */
listIntegers.add(index);
/* Print the records of List */
System.out.println("Producer Thread: \n" + listIntegers);
index++;
}else{
/* Remove 1st element from List */
listIntegers.remove(0);
}
}
}
}
}
/* Consumer thread that will iterate records of `listIntegers` */
public static class ConsumerThread extends Thread{
@Override
public void run() {
while(true){
try {
/* Put thread in sleep for `1 milliseconds` */
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Consumer Thread iterator list: ");
/* synchronized block */
synchronized (listIntegers) {
/* Get iterator of List */
Iterator<Integer> iterator = listIntegers.iterator();
/* Iterate List until last element */
while(iterator.hasNext()){
/* Print the element */
System.out.print(iterator.next() + ", ");
if(!iterator.hasNext()){
System.out.println("");
}
}
}
}
}
}
}