Core java - Advance Topics
  • Welcome
  • Schedule
  • 1) Exception Handling
    • 1) Introduction to Exception Handling
    • 2) Categories of Exceptions
    • 3) Creating a method that throws an exception
    • 4) Creating Custom Exception Classes
    • 5)What happens when an exception is thrown?
      • 5.1) Creating try-catch-finally blocks
      • 5.2) Using a method that throws a checked exception
      • 5.3) Using a method that throws a runtime exception
      • 5.4) Using a method that throws an error
      • 5.5) Will a finally block execute even if the catch block defines a return statement?
      • 5.6) What happens if both a catch and a finally block define return statement?
      • 5.7) What happens if a finally block modifies the value returned from a catch block?
      • 5.8) Can a try block be followed only by a finally block?
      • 5.9) Does the order of the exceptions caught in the catch blocks matter?
      • 5.10) Can I rethrow an exception or the error I catch?
      • 5.11) Can I declare my methods to throw a checked exception instead of handling it?
      • 5.12) I can create nested loops, so can I create nested try-catch blocks too?
      • 5.13) Should I handle errors?
    • 6) Best Practices
    • 7) Cheat Sheet
    • 8) Problems
  • 2) Wrapper Classes and Enums
    • 2.1) Creating objects of the wrapper classes
    • Enums
  • 3) Inner Classes
    • 3.1) Static nested class (also called static inner class)
    • 3.2) Inner class (also called member class)
    • 3.3) Anonymous inner class
    • 3.4) Method local inner classes
    • CheatSheet
  • 4) Generics
    • Multiple Type parameters in Generic classes
    • Inheritance using Generics
    • Generic interfaces
    • Generic Methods
    • Bounded type parameters
    • Applications
  • 5) Equals and Hashcode
    • Problems
  • CompareTo method overview
  • Basic DS
    • 1) Simple Array List
    • 2) Simple HashMap
  • 5) Collections Framework - Part 1
    • Introducing the collections framework
    • Working with the Collection interface
      • The core Collection interface
      • Methods of the Collection interface
    • Creating and using List, Set, and Deque implementations
      • List interface and its implementations
      • Iterators
      • Sorting List using custom sorting technique
      • Comparable Interface
      • Custom Sorting using comparator
      • ArrayList - Examples and practice problems
    • Stack
    • Linked List
    • LinkedList Operations
  • 6) Collections Framework - Part 2
    • Sets
      • Set Types
      • Array to Set (vice versa)
    • Maps
    • TreeMap
    • Autoboxing And Unboxing
  • Collections Framework - Part 3
    • Basics : DS , Number System
    • Internal Working
      • HashMap
      • HashSet
  • 7) Reflection API
  • 8) Annotations
  • 9) Reading Input From Various Sources
    • File Handling
    • Reading From Xml
    • Reading From JSON
  • 10) Multi-threading (Concurrency)
    • Protect shared data
    • Thread-safe access to shared data
  • 11) Design Patterns
    • Singleton
    • DI
  • 12) Internal Working of JVM
  • 13) Garbage Collection
  • 14) More on Strings (Buffer and Builder)
  • 15) Cloning and Immutable Class
    • 16) Serialization And Deserialization
    • Untitled
  • JAVA 8
    • Interface Changes
    • Lambda
    • Method Ref
    • Optional
    • Streams
    • Predicates
  • Practice Tests
    • Test - Collections
    • OOPS
    • S-OOPS
Powered by GitBook
On this page
  • Identifying shared data:
  • Thread interference:
  • Examples:
  • 1)
  • 2)
  • 3) With synchronzation (On object):
  • 4)
  • 5)
  • 6)
  • 7) Synchronized with non-synchronized :
  • 8) Non-synchronized in Synchronized :
  • 9) deadlock?
  • 10) deadlock ?

Was this helpful?

  1. 10) Multi-threading (Concurrency)

Protect shared data

Previous10) Multi-threading (Concurrency)NextThread-safe access to shared data

Last updated 6 years ago

Was this helpful?

Threads are lightweight processes that share certain areas of the memory, unlike regular processes. This makes threads very efficient, but it also introduces additional complexities regarding memory management. You can protect your shared data by making it accessible (for reading and writing) to only one thread at a point of time. Other techniques include defining immutable classes (the states of which can’t be modified and defining volatile variables.

Identifying shared data:

A JVM instance hosts only one Java application. A Java application can create and execute multiple threads. When a new thread is created, it’s allotted its exclusive share in the memory. The JVM also allows partial runtime data to be shared between threads. A JVM’s runtime data set includes the method area, the heap, Java stacks, and PC registers (it also includes native method stacks, which aren’t covered by the exam, so they aren’t discussed here). The method area includes class information that includes a note on all its variables and methods. This data set includes the static variables, which are accessible and shared by all the threads in a JVM. The static vari- ables are shared by one class loader—that is, each class loader has its own set of static variables. The heap includes objects that are created during the lifetime of an application, again shared by multiple threads and processes. PC registers and Java stacks aren’t shared across the threads. On instantiation, each thread gets a PC regis- ter, which defines the next set of instructions to execute. Each thread is also assigned a Java stack. When a thread begins execution of a method, a method frame is created and inserted into the java stack, which is used to store the local variables, method parameters, return values, and intermediate values that might be used in a method.

Thread interference:

Interleaving of multiple threads that manipulate shared data using multiple steps leads to thread interference. You can’t assume that a single statement of Java code executes atomically as a single step by the processor. For example, a simple statement like incrementing a variable value might involve multiple steps like loading of the variable value from memory to registers (working space), incrementing the value, and reloading the new value in the memory. When multiple threads execute this seemingly atomic statement, they might interleave, resulting in incorrect variable values.

Operations that use arithmetic and assignment operators like ++, --, +=, -=, *=, and /= aren’t atomic. Multiple threads that manipulate variable values using these operators can interleave.

Let’s work with an example of a class Book, which defines an instance variable copies- Sold that can be manipulated using its methods newSale() or returnBook():

Let’s see what happens when another class, say, ShoppingCart, instantiates a Book and passes it to the threads OnlineBuy and OnlineReturn:

In the preceding code method main() starts three threads—task1, task2, and task3. These threads manipulate and share the same Book instance, book. The threads task1 and task2 execute book.newSale(), and task3 executes book.returnBook(). As mentioned previously, ++copiesSold and --copiesSold aren’t atomic operations. Also, as a programmer you can’t determine or command the exact time when these threads will start with their execution (it depends on how they’re scheduled to exe- cute by the OS). Let’s assume that task2 starts with its execution and reads book .copiesSold. Before it can modify this shared value, it’s also read by threads task3 and task2, which are unaware that this value is being modified by another thread. All these threads modify the value of book.copiesSold and update it back in order. The last thread to update the value book.copiesSold overrides updates of the other two threads. Figure below shows one of the possible ways in which the threads task1, task2, and task3 can interleave.

So, how can you assure that when multiple threads update shared values it doesn’t lead to incorrect results? How can you communicate between threads? Let’s discuss this in the next section.

Examples:

1)

import java.util.Set;

public class Thread1 {
	public static void main(String[] args) {

		StringBuilder string = new StringBuilder("shared ");

		Thread thread = new ProducerThread(string);
		Thread thread2 = new ConsumerThread(string);

		thread.start();
		thread2.start();

		Set<Thread> seThreads = Thread.getAllStackTraces().keySet();

		seThreads.stream().map(Thread::getName).forEach(System.out::println);

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class ProducerThread extends Thread {
	private StringBuilder string = null;

	public ProducerThread(StringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		int i = 0;
		while (i < 100) {
			i++;
			string.append("prod " + i);
		}
	}
}

class ConsumerThread extends Thread {

	private StringBuilder string = null;

	public ConsumerThread(StringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		int i = 0;
		while (i < 100) {
			i++;
			string.append("cons " + i);
		}
	}
}
I am prod thread
I am con thread
Thread-1
Signal Dispatcher
Finalizer
Attach Listener
main
Thread-0
Reference Handler
shared prod 1prod 2prod 3prod 4prod 5prod 6prod 7prod 8prod 9prod 10prod 11prod 12prod 13prod 14prod 15prod 16prod 17prod 18prod 19prod 20prod 21prod 22prod 23prod 24prod 25prod 26prod 27prod 28prod 29prod 30prod 31prod 32prod 33prod 34prod 35prod 36prod 37prod 38prod 39prod 40prod 41prod 42prod 43prod 44prod 45cons 1cons 2cons 3prod 46cons 4cons 5cons 6cons 7cons 8prod 47cons 9cons 10prod 48

2)

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		Thread thread2 = new ConsumerThread(string);

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		int i = 0;
		while (i < 100) {
			i++;
			string.getString().append("prod " + i);
		}
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		int i = 0;
		while (i < 100) {
			i++;
			string.getString().append("cons " + i);
		}
	}
}
I am prod thread
I am con thread
shared prod 1prod 2prod 3prod 4prod 5prod 6prod 7prod 8prod 9prod 10prod 11prod 12prod 13prod 14prod 15prod 16prod 17prod 18prod 19prod 20prod 21prod 22prod 23prod 24prod 25prod 26prod 27prod 28prod 29prod 30prod 31prod 32prod 33cons 1prod 34cons 2prod 35cons 3prod 36cons 4cons 57

3) With synchronzation (On object):

import java.util.Set;

public class Thread1 {
	public static void main(String[] args) {

		StringBuilder string = new StringBuilder("shared ");

		Thread thread = new ProducerThread(string);
		Thread thread2 = new ConsumerThread(string);

		thread.start();
		thread2.start();

		Set<Thread> seThreads = Thread.getAllStackTraces().keySet();

		seThreads.stream().map(Thread::getName).forEach(System.out::println);

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class ProducerThread extends Thread {
	private StringBuilder string = null;

	public ProducerThread(StringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		synchronized (string) {
			int i = 0;
			while (i < 100) {
				i++;
				string.append("prod " + i);
			}
		}
	}
}

class ConsumerThread extends Thread {

	private StringBuilder string = null;

	public ConsumerThread(StringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		synchronized (string) {
			int i = 0;
			while (i < 100) {
				i++;
				string.append("cons " + i);
			}
		}
	}
}

4)

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		Thread thread2 = new ConsumerThread(string);

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public synchronized StringBuilder getString() {
		return string;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		int i = 0;
		while (i < 100) {
			i++;
			string.getString().append(" prod" + i);
		}
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		int i = 0;
		while (i < 100) {
			i++;
			string.getString().append("cons" + i);
		}
	}
}

5)

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		Thread thread2 = new ConsumerThread(string);

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	public  void myAppend(String str) {
		int i = 0;
		while (i < 100) {
			i++;
			string.append(str + i);
		}

	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		string.myAppend(" prod ");
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		string.myAppend(" cons ");
	}
}

6)

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		Thread thread2 = new ConsumerThread(string);

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	public synchronized void myAppend(String str) {
		int i = 0;
		while (i < 100) {
			i++;
			string.append(str + i);
		}

	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		string.myAppend(" prod ");
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		string.myAppend(" cons ");
	}
}

7) Synchronized with non-synchronized :

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		thread.setName("Producer Thread");
		Thread thread2 = new ConsumerThread(string);
		thread2.setName("consumer Thread");

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	public synchronized void myAppend(String str) {
		int i = 0;
		while (i < 100) {
			i++;
			synchronized (string) {				
				string.append(str + i);
			}
		}

	}

	public void nonSychronizedMyAppend(String str) {
		int i = 100;
		while (i < 200) {
			i++;
			string.append(str + i);
		}

	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		string.myAppend(" prod ");
		string.nonSychronizedMyAppend(" prodNon ");
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		string.nonSychronizedMyAppend(" consNon ");
		string.myAppend(" cons ");
	}
}

8) Non-synchronized in Synchronized :

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		thread.setName("Producer Thread");
		Thread thread2 = new ConsumerThread(string);
		thread2.setName("consumer Thread");

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	public synchronized void myAppend(String str) {
		int i = 0;
		while (i < 100) {
			i++;
			string.append(str + i);
		}
		nonSychronizedMyAppend(str + "non");
	}

	public void nonSychronizedMyAppend(String str) {
		int i = 100;
		while (i < 200) {
			i++;
			string.append(str + i);
		}

	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		string.myAppend(" prod ");
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		string.myAppend(" cons ");
	}
}

9) deadlock?

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string = new MyStringBuilder(new StringBuilder("shared "));

		Thread thread = new ProducerThread(string);
		thread.setName("Producer Thread");
		Thread thread2 = new ConsumerThread(string);
		thread2.setName("consumer Thread");
		
		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	public synchronized void myAppend(String str) {
		int i = 0;
		while (i < 100) {
			i++;
			string.append(str + i);
		}

	}
	
	public synchronized void myAppend2(String str) {
		int i = 100;
		while (i < 200) {
			i++;
			string.append(str + i);
		}

	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string = null;

	public ProducerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		string.myAppend(" prod ");
		string.myAppend2(" prodNon ");
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string = null;

	public ConsumerThread(MyStringBuilder string) {
		this.string = string;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		string.myAppend2(" consNon ");
		string.myAppend(" cons ");
	}
}

10) deadlock ?

public class Thread1 {
	public static void main(String[] args) {

		MyStringBuilder string1 = new MyStringBuilder(new StringBuilder("resource_one "));
		MyStringBuilder string2 = new MyStringBuilder(new StringBuilder("resource_two "));

		Thread thread = new ProducerThread(string1, string2);
		thread.setName("Producer Thread");
		Thread thread2 = new ConsumerThread(string2, string1);
		thread2.setName("consumer Thread");

		thread.start();
		thread2.start();

		try {
			thread.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(string1);
		System.out.println(string2);
	}
}

class MyStringBuilder {
	StringBuilder string;

	MyStringBuilder(StringBuilder string) {
		this.string = string;
	}

	public void setString(StringBuilder string) {
		this.string = string;
	}

	public StringBuilder getString() {
		return string;
	}

	public synchronized void myAppend(String str) {
		int i = 0;
		while (i < 100) {
			i++;
			string.append(str + i);
		}

	}

	public synchronized void myAppend2(String str) {
		int i = 100;
		while (i < 200) {
			i++;
			string.append(str + i);
		}

	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return string.toString();
	}
}

class ProducerThread extends Thread {
	private MyStringBuilder string1 = null;
	private MyStringBuilder string2 = null;

	public ProducerThread(MyStringBuilder string1, MyStringBuilder string2) {
		this.string1 = string1;
		this.string2 = string2;
	}

	@Override
	public void run() {
		System.out.println("I am prod thread");
		string2.myAppend2(" prod ");
		string1.myAppend(" prodNon ");
	}
}

class ConsumerThread extends Thread {

	private MyStringBuilder string1 = null;
	private MyStringBuilder string2 = null;

	public ConsumerThread(MyStringBuilder string1, MyStringBuilder string2) {
		this.string1 = string1;
		this.string2 = string2;
	}

	@Override
	public void run() {
		System.out.println("I am con thread");
		string2.myAppend(" consNon ");
		string1.myAppend2(" cons ");
	}
}