My All Core Java Interview Questions
My All Core Java Interview Questions
1. Both of objects exist independently, and none of them is owner of each other, but they can use each other.
2. Both are separate Entity, and they have their own lifestyle, Manager can stay without swipe-card and swipe-card can
stay without manager.
Aggregation Code :- (Manager has many workers under him)
Now what it says is that means Manager is an owner of the worker in other words workers only belongs to the
owner which means that the Manager have a list of the workers.
Here workers actually belongs to the manager that means the Manager is the Owner of these workers but still
the workers can be created separately, we can create an object of worker without thinking the Manager
means we can still use worker independently.
So, in this kind of relationship, we have one and only one owner like previous swipe card is not the owner of the
manager that can only belongs to.
Composition Code: - (Manager salary depends on project success and the project success depends on
Manager)
Now if the project is successful then manager salary got incremented and now if manager is working properly
then project will be get successful.
Here Manager status is depending on how the project status is going.
So, manager needs the Project object and Project needs the Manager objects both are highly dependable we
can say this one is as a Death Relationship.
Q2. Prevent Breaking a Singleton Class Pattern (Reflection, Cloning and Deserialization)
There are mainly three concepts in which we can break the singleton property of a Singleton class in Java. In
this post, we will discuss how it can break and how to prevent it.
Here is sample Singleton class and SingletonTest class.
Singleton.Java
-------------------
package demo1;
public final class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
SingletonTest.java
------------------
package demo1;
public class SingletonTest {
public static void main(String[] args) {
Singleton object1 = Singleton.getInstance();
Singleton object2 = Singleton.getInstance();
System.out.println("Hashcode of Object 1 - " + object1.hashCode());
System.out.println("Hashcode of Object 2 - " + object2.hashCode());
}
}
Here is output; you can see it has the same hashcode for objectOne and objectTwo:
Hashcode of Object 1 - 1836019240
Hashcode of Object 2 - 1836019240
>> Now, we will break this pattern. First, we will use Java reflection.
>> Reflection
Java Reflection is an API used to examine or modify the behavior of methods, classes, and interfaces at
runtime. Using the Reflection API, we can create multiple objects in the Singleton class. Consider the following
example:
ReflectionSingleton.java
----------------------------------
public class ReflectionSingleton {
public static void main(String[] args) {
Singleton objOne = Singleton.getInstance();
Singleton objTwo = null;
try {
Constructor constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
objTwo = (Singleton) constructor.newInstance();
} catch (Exception ex) {
System.out.println(ex);
}
System.out.println("Hashcode of Object 1 - "+objOne.hashCode());
System.out.println("Hashcode of Object 2 - "+objTwo.hashCode());
}}
This example shows how reflection can break the singleton pattern with Java reflect. You will get two hash
codes, as shown below. It has a break on the singleton pattern.
>> Deserialization
In serialization, we can save the object of a byte stream into a file or send over a network. Suppose if you
serialize the Singleton class, and then again de-serialize that object, it will create a new instance, hence
deserialization will break the Singleton pattern.
The below code is used to illustrate how the Singleton pattern breaks with deserialization.
DeserializationSingleton.Java
----------------------------------------
public class DeserializationSingleton {
public static void main(String[] args) throws Exception {
Singleton instanceOne = Singleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("file.text"));
Singleton instanceTwo = (Singleton) in.readObject();
in.close();
System.out.println("hashCode of instance 1 is - " + instanceOne.hashCode());
System.out.println("hashCode of instance 2 is - " + instanceTwo.hashCode());
}}
The output is below, and you can see two hashcode
hashCode of instance 1 is - 2125039532
hashCode of instance 2 is – 38125935
>> Cloning
Using the "clone" method, we can create a copy of the original object; it's the same thing if we applied clone in
the singleton pattern. It will create two instances: one original and another one cloned object. In this case, we
will break the Singleton principle, as shown in the below code.
Implement the " Cloneable" interface and override the clone method in the above Singleton class.
Singleton.java
-------------------
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
CloningSingleton.java
------------------------------
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
Now, we can run the CloningSingleton class; it will throw CloneNotSupportedException while creating a clone
object of the Singleton object .
Double hashing is a collision resolving technique in Hash tables. Double hashing uses the idea of applying a
second hash function to key when a collision occurs.
A popular second hash function is: hash2(key) = PRIME – (key % PRIME) where PRIME is a prime smaller than
the TABLE_SIZE.
A good second Hash function is:
It must never evaluate to zero
Must make sure that all cells can be probed
Note:--
When write:-
Map<String,Integer> map=new HashMap<String,Integer>();
By default created Bucket size= 16
List<Integer> list=new ArrayList<Integer>();
By default initial capacity= 10…
After filled all 10 its size increased by 50% so it would be 15
Q4. What are the best Rest Principle you keep in mind when you create REST end
point, the best practises u follows?
a. Don't return plain text
you can verify a reponse's Content-Type very easily with Firefox. It has built-in pretty-display for
responses with Content-Type: application/json.
b. Avoid using verbs in URIs
This is because HTTP verbs should be sufficient to describe the action being performed on the
resource.
# Don't
POST: /articles/createNewArticle/
# Do
POST: /articles/
C. How we can Implement the Bean Validation and Input Request Validation in our Backend
You need to restrict to the user to give the correct inputs, you can do it use Backend. So, no use to
store invalid format data into your db, otherwise it will impact your business.
we just need to mention in the POST Controller method @Valid to validate this particular request
with @Request Body. and for User Request Bean we just need to annotate field with all required
annotation like for name @NotNull, for email @Email, for age @Min(18) and @Max(60) for mobile
@Pattern(^\\d{10}$)
d. Return error details in the response body
When an API server handles an error, it is convenient (and recommended!) to return error details in
the JSON body to help users with debugging. Special kudos if you include which fields were affected
by the error!
{
"error": "Invalid payoad.",
"detail": {
"surname": "This field is required."
}
}
e. Use status codes consistently
400: Bad Request response
404: Resource Not Found
500: Internal server Error
401: UNAUTHORIZED HTTP RESPONSE
403: FORBIDDEN
201: Created
204: No Content
GET: 200 OK
POST: 201 Created
PUT: 200 OK
PATCH: 200 OK
DELETE: 204 No Content
FORBIDDEN: 401
GET: /authors/12/articles/
GET: /articles/?author_id=12
My recommendation is to use the query string to filter the articles resource directly:
This clearly means: "get all articles for author #12"
GET: /articles/?page=1&page_size=10
Authentication confirms that users are who they say they are. Authorization gives those users
permission to access a resource.
complete an authentication process through:
Passwords. Usernames and passwords are the most common authentication factors. If a
user enters the correct data, the system assumes the identity is valid and grants access.
One-time pins. Grant access for only one session or transaction.
Authentication apps. Generate security codes via an outside party that grants access.
Biometrics. A user presents a fingerprint or eye scan to gain access to the system.
Authorization in a system security is the process of giving the user permission to access a specific
resource or function. This term is often used interchangeably with access control or client privilege.
Java 8 Stream has many operations which can be pipelined together to get desired result. Some
operations produce another stream as a result and some operations produce non-stream values as a
result. The operations which return another stream as a result are called intermediate operations
and the operations which return non-stream values like primitive or object or collection or return
nothing are called terminal operations.
1) The main difference between intermediate and terminal operations is that intermediate
operations return a stream as a result and terminal operations return non-stream values like
primitive or object or collection or may not return anything.
2) As intermediate operations return another stream as a result, they can be chained together to
form a pipeline of operations. Terminal operations cannot be chained together.
3) Pipeline of operations may contain any number of intermediate operations, but there has to be
only one terminal operation, that too at the end of pipeline.
4) Intermediate operations are lazily loaded. When you call intermediate operations, they are
actually not executed. They are just stored in the memory and executed when the terminal
operation is called on the stream.
5) As the names suggest, intermediate operations don’t give end result. They just transform one
stream to another stream. On the other hand, terminal operations give end result.
6) Intermediate Operations :
Terminal Operations :
SOAP is a standard protocol for creating web services. REST is an architectural style to create web services.
SOAP is acronym for Simple Object Access Protocol. REST is acronym for REpresentational State Transfer.
SOAP uses WSDL to expose supported methods and REST exposes methods through URIs, there are no
technical details. technical details.
SOAP web services and client programs are bind with REST doesn’t have any contract defined between
WSDL contract server and client
SOAP web services and client are tightly coupled with REST web services are loosely coupled.
contract.
SOAP learning curve is hard, requires us to learn REST learning curve is simple, POJO classes can be
about WSDL generation, client stubs creation etc. generated easily and works on simple HTTP methods.
SOAP supports XML data format only REST supports any data type such as XML, JSON,
image etc.
SOAP web services are hard to maintain, any change REST web services are easy to maintain when
in WSDL contract requires us to create client stubs compared to SOAP, a new method can be added
again and then make changes to client code. without any change at client side for existing
resources.
SOAP web services can be tested through programs or REST can be easily tested through CURL command,
software such as Soap UI. Browsers and extensions such as Chrome Postman.
Service discovery is how applications and (micro)services locate each other on a network. Service
discovery implementations include both:
o A central server (or servers) that maintain a global view of addresses and
o Clients that connect to the central server to update and retrieve addresses.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Note: we can check the latest Spring Cloud releases in the Spring's Projects documentation.
Next, we're creating the main application class:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Finally, we're configuring the properties in YAML format; so, an application.yml will be our
configuration file:
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
Here we're configuring an application port – 8761 is the default one for Eureka servers. We are
telling the built-in Eureka Client not to register with ‘itself' because our application should be acting
as a server.
Now we'll point our browser to http://localhost:8761 to view the Eureka dashboard, where we will
later inspecting the registered instances.
A typical distributed system consists of many services collaborating together. These services are
prone to failure or delayed responses. If a service fails it may impact on other services affecting
performance and possibly making other parts of application inaccessible or in the worst case bring
down the whole application.
So, of course, there are solutions available that help make applications resilient and fault tolerant
– one such framework is Hystrix.
The Hystrix framework library helps to control the interaction between services by providing fault
tolerance and latency tolerance. It improves overall resilience of the system by isolating the failing
services and stopping the cascading effect of failures.
In this series of posts, we will begin by looking at how Hystrix comes to the rescue when a service or
system fails and what Hystrix can accomplish in these circumstances.
Commonly used for Authorization. Idea behind JWT is to create a standard way for 2 parties to
communicate securely.
When user first time get login or authorize then browser create a session id and it sends to user with
response and that session id stored to the cookies, next time when user sends subsequent request
then with request header cookies sessionid will come and it says it’s a same user
Now the biggest problem with session id is assume something.
JWT is not for authentication it is for future authorization purpose used for further interactions.
Server says ok I am authenticated you in order to me for remember who you are into subsequent
interaction.
So, JWT is specific to authorization. JWT comes into picture when only authentication is complete.
Server creates the JWT it has the payload, with Header also there and just Signed there and sign is
Strictly associated with the Values which is like JWT- Header and Payload.
When client gets the JWT it can store either in a Local storage or inside the cookies. It doesn’t matter
and client just passes JWT in subsequent Request with HTTP Header, HTTP Headers are key value
pairs. so, the key for passing this according to the JWT standard is called authorization and the value
is the word Bearer followed by space followed by JWT. So, the clients on every subsequent requests
put this in a Header and sends it to the server.
The server examines the request checks this value in Header, says ok the authorization I have the
JWT ,now splits this into 3 parts figures out what the payload is. it just have to do the Base64 Decode
that will give the value. it just has to verify that the value is valid.
It just follows the formula it just does the Base64 Encode of Header and Payload and then it
calculates the signature for It. And verify that it is matches the signature which is generated through
the secret key. If Matches, then It trust. That this JWT with valid signature. If not matches means
Invalid user.
Here there is nothing on the server all are in JWT, u can set an expiration for JWT.
How to do logoff in JWT is tricky, bcz nothing is there onto the server. the people handle this by
some blacklisted JWT, let’s say the server issued me the JWT and I tell the server that somebody
stolen my JWT then what the server can do. on the server its maintain the List of Blacklisted JWT, ok
this particular JWT is blacklisted. if someone try to access with the blacklisted JWT then compare and
say Invalid JWT.
So, Resource server and Authorization server are usually coupled. So, Authorization server could be a
separate server or along with Resource Server.
How it works>>>
Client thinks this guy don’t give me access directly bcz that guy is using OAuth, so first I need to talk
to Authorization Server.
So, Resource owner says yes, I am the only person who ask to access google, so give them access.
Authorization server said OK I got a confirmation from the Resource owner so I am giving a token so
u can access.
Authorization Token - > Auth Token, the client uses this authorization Token and contact the
Authorization server to get a second Token which is the Access Token.
Now the Access Token is like a Key to access the Resource from Resource Server.
UseCase->
OAuth uses for Authorization between services.
Spring supports multiple types of annotations such as @Component, @Controller, @service @Repository and @Bean. All
these can be found under the org.springframework.stereotype package.
When classes in our application are annotated with any of the above-mentioned annotation then during project start up
spring scan (using @componentScan) each class and inject the instance of the classes to the IOC container. Another thing
the @ComponentScan would do is running the methods with @Bean on it and restore the return object to the Ioc
Container as a bean.
1 Auto detection It is used to explicitly declare a single If any class is annotated with @Component
bean, rather than letting Spring do it it will be automatically detect by using
automatically. classpath scan.
2 Spring Container Bean can be created even class is outside We can’t create bean if class is outside
the spring container spring container
Annotation
5 Use Case We should use @bean, if you want We can’t write specific implementation
specific implementation based on based on dynamic condition
dynamic condition.
Example of @Component
@Component
public class Pizza{
........
}
Example of @Bean
@Configuration
class AppConfiguration{
@Bean
public User getUse(){
return new User();
}
}
Q 14. The hierarchy of exceptions
Exceptions and errors are represented through Java classes, and they are organized in a hierarchy.
The class Throwable is the superclass of all types of errors and of all exceptions. Errors represent
events that cannot be controlled by the programmer (for example, OutOfMemoryError), while
exceptions can be handled during the execution of the program.
Q 15. Difference between @BeforeAll and @BeforeEach
The code marked @Before is executed before each test, while @BeforeClass runs once before the
entire test fixture. If your test class has ten tests, @Before code will be executed ten times,
but @BeforeClass will be executed only once.
In general, you use @BeforeClass when multiple tests need to share the same computationally
expensive setup code. Establishing a database connection falls into this category. You can move code
from @BeforeClass into @Before, but your test run may take longer. Note that the code
marked @BeforeClass is run as static initializer, therefore it will run before the class instance of your
test fixture is created.
In JUnit5, the tags @BeforeEach and @BeforeAll are the equivalents of @Before and @BeforeClass in JUnit 4.
Their names are a bit more indicative of when they run, loosely interpreted: 'before each tests' and 'once
before all tests'.
Both ClassNotFoundException is an exception and NoClassDefFoundError are the error which occur when
JVM or ClassLoader not able to find appropriate class while loading at run-time.
ClassNotFoundException is a checked exception and NoClassDefFoundError is an Error which comes
under unchecked.
AtomicInteger
Volatile
Synchronized method / block
Thread Local
Lock/ Reentrant Lock
Another way-
Any Contract between Client and Service Provider is called Interface. That means what set of
services clients is expecting and what set of services Service provider is providing. that contract
specification is called Interfaces.
*** 100 % pure Abstract class, (but from java 1.8 inside interface default method allow, static
method allow, from java 1.9 private methods are allow) so we can Ignore this.
If the Implementation of a class is not complete such type of partially implemented class
declared as an Abstract class.
If a class contains at least one abstract method, then compulsory that class must be declared as
an Abstract class and Object creation of that class is not possible.
If a class doesn’t contain any abstract method, then if we feel the class is an inappropriate then
happily, we can declare that class as an Abstract class to restrict the creation of an Object.
If the Implementation of a class is not complete or dummy Implementation then I don’t want to
create an object of that class then happily we should declare that class as an Abstract even
though that class doesn’t have any abstract method, because no use to creation of an object.
Example:-
So, if a class declared as Abstract means partially Implemented class… so if you feel the implementation of a
class is inappropriate or improper then we can happily declare that type of class as Abstract class.
If I declared a class as an Abstract, then no one is allowed to create the Object or no one is allowed to call
these methods.
Example
*** Adapter class doesn’t contain any Abstract methods then also they declared as an Abstract, bcz some methods
having only curly open and close braces so no use.
*** HttpServlet class: even this class also not contains abstract methods.
1. If we don’t know anything about Implementation just, 1. If we are talking about Implementation but not
we have requirement specification then we should go completely (partial Implementation) then we should go
for Interface. for Abstract class.
2. Inside Interface every method is always public and 2 Every method present in Abstract class need not be
abstract whether we are declaring or not. Hence public and abstract, It can contains concrete methods
Interface is also considered as 100% pure abstract also.
class.
3. We can’t declare interface method with the following 3 There are no restrictions on Abstract class method
modifiers. modifiers.
Public private, protected
Abstract- final, static, synchronized, native, strictfp
4. Every variable present inside interface is always public, 4 The variables present inside Abstract class need not be
static and final whether we are declaring or not. public static and final.
5. Transient keyword not applicable with Interface bcz
Serialization not applicable for Interface bcz we can’t
create object for interface.
6 We can’t declare interface variables with the following 6 There are no restrictions on Abstract class variable
modifiers. modifiers.
Private, protected, transient, volatile (bcz it is final so can’t
volatile means keep on changing)
7 for Interface variables compulsory we should perform 7 for Abstract class variables it is not required to perform
initialization at the time of declaration otherwise we ll get initialization at time of declaration.
compile time error.
So int x; // will throw error
8 Inside Interface we can’t declare instance and static blocks 8 Inside Abstract class we can declare instance and static
otw we ll get compile time error. blocks.
9. Constructor concept not applicable for Interface bcz the 9 Inside Abstract class we can declared constructor which
purpose of constructor is initialized the instance variables will be executed at the time of child object creation.
but within an interface every variables is always static and
initialized .
Data hiding means outside persons should not access our data directly by declaring private variable or by declaring
our variable at the private we can implement data hiding.
Abstraction means hiding Internal Implementations just highlight the setup services what we are offering is a concept
of abstraction.
If u are feeling cold, then immediately we are going to use cold act capsule. So, some medicine will be there inside the
capsule. So whatever medicine required to cure the cold that medicine is encapsulated.so medicine is going to be
grouped inside the capsule.so it is going to be grouped or a single unit of medicine inside the capsule…
Class Student
{
String name;
Int age;
Int marks;
+
Read();
Write();
}
The process of Grouping or combining data members and corresponding methods or behavior into a single unit is a
concept of encapsulation. So capsule means grouping mechanism.
So, every java class is an example of Encapsulation.
Now Practically,
If any Component follows data hiding and abstraction that component is said to be encapsulated component.
Class Account
{
Private double balance;
Public double getBalance()
{
//validate (uname and pwd either person is correct person or not)
If person is valid
return balance;
}
So here bcz of private outside person can’t access the account balance so how outside person can access for that we are
providing the getter and setter methods. So, the benefit of access data from setter and getter is the required validations. So
outside person only to get the data either the setter or getter operation after the required validations.
Summary: -
1. Grouping data members and corresponding methods into a single unit is a concept of Encapsulation.
2. If any Component follows data hiding and abstraction that component is said to be encapsulated
component.
3. So, declare members as a private and for every data member provide getter and setter methods and
we can provide access through GUI screen called Encapsulation.
4. So through getBalance () and setBalance () only we are going to provide the data so getBalance () and
setBalance() is either Interface for outside persons….internally our data is going to comes so that’s y
hiding the data behind the methods.
5. So, Hiding the data inside the methods is called encapsulations.
6. Advantage: - 1. security achieve 2. Enhancement – we can perform any type of changes internally….
3. Maintainability and Modularity.
7. Disadvantage: every member req setter and getter…and validations required so more no . of line of
code slow execution so wherever security required then only go to use Encapsulation.
2. Abstraction:-
Hiding Internal Implementation just highlights the set of services what we are going to offer is the
concept of abstraction. By using GUI concepts or some Interfaces we can Implements the
Abstractions. Using GUI, we can maintain the abstraction
Example: - ATM GUI Screens
when we are going to ATM machine…
We can change technology itself by maintaining same GUI frame. In ATM when click on withdraw
previously written code in java again new technology came YAVA….so only we can change our
internal implementations without changing GUI itself.
3. Polymorphism
One name but multiple forms, (Polytechnique means many technologies are coming)
Method Overloading and Method Overriding is the best example for the Polymorphism.
package com.home.java;
public class Parent
{
public static void foo() {
System.out.println("Inside foo method in parent class");
}
package com.home.java;
public class Child extends Parent
{
// Hiding
public static void foo() {
System.out.println("Inside foo method in child class");
}
// Overriding
public void bar() {
System.out.println("Inside bar method in child class");
}
}
package com.home.java;
public class MainApp
{
public static void main(String[] args) {
Parent p = new Parent();
Parent c = new Child();
System.out.println("****************Method Hiding*******************");
p.foo(); // This will call method in parent class
c.foo(); // This will call method in parent class
System.out.println("****************Method overriding*******************");
p.bar(); // This will call method in parent class
c.bar(); // This will call method in child class
}
}
output:-
****************Method Hiding*******************
Inside foo method in parent class
Inside foo method in parent class
****************Method overriding*******************
Inside bar method in parent class
Inside bar method in child class
4. Inheritance: -
Inheritance is a process where child class acquires the properties of super class.
We can generate Thread Dump…either J VisualVM, which Is under jdk or through command
prompt using Jstack…..
Vector will grow 100% of its size when ArrayList 50% of his size.
Vector - Synchronized
ArrayList: - Not Synchronized
Fork-Join Pool:-
Exactly the same as ExecutorService….Internally just uses double ended queue for each of the
threads…
And all of the sub-tasks that each thread produces they are all stored into their all double ended queue…..
How to submit that tasks to Executor service
No changes now if u work with fork join tasks, then u have to use these special methods……
So, Fork join Task is a class build internally, to create a kind of task which can produce sub tasks.
how ForkJoinPool works
https://www.youtube.com/watch?v=5wgZYyvIVJk
As volatile keyword is not cached in CPU, it is always read from main memory, so in terms of performance it’s always expensive to use
volatile keyword.
Can subclass avoid Serialization if its superClass has implemented Serialization interface in java
If superClass has implemented Serializable that means subclass is also Serializable (as subclass always inherits all features
from its parent class), for avoiding Serialization in sub-class we can define writeObject() method and throw
NotSerializableException() from there as done below.
To visualize this->
When we are submitting a task for callable, it immediately giving the placeholder value, which will give the
future value bcz service.submit won’t give result after submit it will give in future….but it will give the
placeholder value from which we can get result by future.get() method.
When we used future.get () doing the Blocking operation, when we call future.get () from main thread it will block the main
thread to perform any task once pool returns the placeholder value then main thread and runnable. When we have
submitted more tasks to pool submitted 4 tasks then pool won’t guarantee that task one will complete before 3 and task 4.
the problem was Even though there are many tasks which has been completed since we are using a for loop
for future.get () we are not be able to do anything from 7 and 5. Until the value 1st task is completed.
Let’s take one example
Let’s say we have certain set of code which divided into certain methods and each method is responsible for the
particular task. So, let’s we have a method for above all so for an order flow we have 5 particular tasks.
So here these all blocking the main thread until future is not completed future.get() if one or 2 tasks
completed we are not be able to do anything until all tasks completed.
It is like sequential operation if there is a dependency on Enrich order of Fetch order bcz enrich order
can’t work until fetch order is completed so there is some certain dependency for these tasks. If multiple threads
running like one doing fetch order another doing enrich order.
So, if we need the scale of our ordering process what I want is we want say n number of threads, in this
case 10 threads all doing the processing for one particular flow. So, we need independent flow so in one flow
tasks are dependent on each other but one flow can’t depends on another flow.
We don’t even care how the task is executing and most important thing is we don’t want main thread to be
block. This is what exactly completable future are designed for.
Class Level Lock: - Its mainly used to make static level data thread safe.
Object level Lock: - This can always be done to make instance-level data thread-safe.
What is serialVersionUID? Impact of not defining serialVersionUID in class and avoiding InvalidClassException in
java
ArrayList, HashSet and HashMap implements Serializable interface, so if we will use them as member of class they will get Serialized and
DeSerialized as well.
If Serializable has been implemented - constructor is not called during DeSerialization process.
But, if Externalizable has been implemented - constructor is called during DeSerialization process.
CountDownLatch countDownLatch;
MyRunnable(CountDownLatch countDownLatch){
this.countDownLatch=countDownLatch;
}
for(int i=2;i>=0;i--){
countDownLatch.countDown();
System.out.println(Thread.currentThread().getName()+
" has reduced latch count to : "+ i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CountDownLatchTest {
2.1) Let’s discuss output in detail, to get better understanding of CountDownLatch usage in program in java >
Note: I have mentioned output in green text.
package CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
/*
* Create CountDownLatch with 3 parties, when all 3 parties
* will reach common barrier point CyclicBarrrierEvent will be
* triggered i.e. run() method of CyclicBarrrierEvent will be called
*/
CyclicBarrier cyclicBarrier=new CyclicBarrier(3 ,new CyclicBarrrierEvent());
System.out.println("CountDownLatch has been created with parties=3,"
+ " when all 3 parties will reach common barrier point "
+ "CyclicBarrrierEvent will be triggered");
MyRunnable myRunnable1=new MyRunnable(cyclicBarrier);
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" is waiting for all other threads to reach common barrier point");
try {
Thread.sleep(1000);
/*
* when all 3 parties will call await() method (i.e. common barrier point)
* CyclicBarrrierEvent will be triggered and all waiting threads will be released.
*/
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
class CyclicBarrrierEvent implements Runnable{
public void run() {
System.out.println("As all threads have reached common barrier point "
+ ", CyclicBarrrierEvent has been triggered");
}
}
/*OUTPUT
CountDownLatch has been created with parties=3, when all 3 parties will reach common barrier point CyclicBarrrierEvent will be triggered
Thread-1 is waiting for all other threads to reach common barrier point
Thread-2 is waiting for all other threads to reach common barrier point
Thread-3 is waiting for all other threads to reach common barrier point
As all threads have reached common barrier point , CyclicBarrrierEvent has been triggered
As all threads have reached common barrier point Thread-1 has been released
As all threads have reached common barrier point Thread-3 has been released
As all threads have reached common barrier point Thread-2 has been released
*/
1. First let’s discuss Similarity between CyclicBarrier and CountDownLatch in Java. CyclicBarrier and CountDownLatch are
similar because they wait for specified number of thread to reach certain point and make count/parties equal to 0.
But, for completing wait in CountDownLatch specified number of threads must call countDown () method in Java. for completing wait in
CyclicBarrier specified number of threads must call await () method in Java.
3. This is very important difference between CyclicBarrier and CountDownLatch in java . CyclicBarrier can be awaited repeatedly, but
CountDownLatch can’t be awaited repeatedly. i.e. once count has become 0 cyclicBarrier can be used again but CountDownLatch cannot
be used again in Java.
4. Another important difference between CyclicBarrier and CountDownLatch in java. CyclicBarrier can be used to trigger event, but
CountDownLatch can’t be used to launch event. i.e. once count has become 0 cyclicBarrier can trigger event in Java but CountDownLatch
can’t.
What is java. util.concurrent.locks.Lock in java?
The java.util.concurrent.locks.Lock is an interface, and its implementations provide more extensive locking operations than
can be obtained using synchronized methods and statements.
A lock helps in controlling access to a shared resource by multiple threads. Only one thread at a time can acquire the
lock and access the shared resource.
If a second thread attempts to acquire the lock on shared resource when it is acquired by another thread, the second
thread will wait until the lock is released. In this way we can achieve synchronization and race conditions can be avoided.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest {
public static void main(String[] args) {
Lock lock=new ReentrantLock();
MyRunnable myRunnable=new MyRunnable(lock);
new Thread(myRunnable,"Thread-1").start();
new Thread(myRunnable,"Thread-2").start();
}
}
System.out.println(Thread.currentThread().getName()
+" is Waiting to acquire lock");
lock.lock();
System.out.println(Thread.currentThread().getName()
+" has acquired lock.");
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()
+" is sleeping.");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+" has released lock.");
lock.unlock();
}
}
/*OUTPUT
Thread-1 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock
Thread-1 has acquired lock.
Thread-1 is sleeping.
Thread-1 has released lock.
Thread-2 has acquired lock.
Thread-2 is sleeping.
Thread-2 has released lock.
*/
6.1) Let’s discuss output in detail, to get better understanding of ReentrantLock usage in program in java >
Note : I have mentioned output in green text.
Thread-1 is sleeping.
Thread-1 has released lock.
Thread-1 has released lock by calling unlock() method. (Now lock hold count=0)
Thread-2 is sleeping.
Thread-2 has released lock.
Loading
you have bootstrap class loader, which is responsible for loading Java's internal classes.
So where does that internal class reside? The internal classes are inside the rt.jar that is
distributed with your JVM implementation. So, just go to the JRE folder and you might
find the rt.jar under there. So that is the bootstrap class loader.
Now going into extension class loader i.e the second-class loader that gets executed
which is responsible of loading additional application jars that are present in jre/lib/ext
folder. So, whatever jars that are present in jre/lib/ext folder is extension class loader. It
will load and read all the dot class files from those jars and give it out for the further
processing.
So, last class loader is application class loader. The application class loader loads classes
from values specified in your classpath environment variable and if you specify a minus
CP parameter with the Java command, the application class loader loads classes from that
minus CP parameter as well. So those are the three different class loaders in the load
phase.
Linking
So going on to the next phase, which is the link phase. So, the link phase is where a lot of
work is done. The link phase itself has three different phases.
<>First is verify. <>Second is prepare. <>Third is resolve.
The verify phase basically looks at the bytecode that is loaded by the class loader and
checks if that is compatible to the JVM class specification and things like that. So, that is
the verification phase. So, you have to first verify the bytecode that is handed to me if it is
a valid Java bytecode. So, that is the class verification.
Once it is verified, the prepare step happens. So, the prepare step is the place where
memory is allocated for the static variables inside a class file. So, you might have private
static integer So, it's a class level variable. So, the memory for that class level variable is
allocated in the prepare phase. So, the most important point that you should note at this
point is that it's only memory allocation that is happening and that is only for the class
variables, not for the instance variables. So, since it is just the memory allocation what
happens is those memory locations are initialized to default values. Suppose you have a
variable like public static boolean isCorrect=true. But at prepare phase, memory will
be allocated for boolean, and it will be set to its default value, which is false as per JVM
specification.
Now comes the resolve phase. So, the resolve phase is the place where all the symbolic
references inside the current class are resolved. "Symbolic references" are strings that
can be used to retrieve the actual object . Suppose you have references to other classes or
references to values in the constant pool. These are changed from symbolic to the actual
reference.
So, those are the three steps involved in link phase, which is verify, prepare and resolve.
Initialize
The next phase of class loading subsystem is initializing. So, this is the phase where static
initializers of your class is run. Suppose you have a static block, static open parenthesis, close
parenthesis. Anything under that static block is executed at this initialized phase and
wherever you have set values for static variables, those values are set into the memory
location at this phase. So, in the prepare phase, for example we talked about a public boolean
is correct equal to true. So, when its memory was allocated, it was set to false initially and
now in the initialized phase, its actual value that we mentioned in the code is set to that
memory area. So those are the three different phases involved in class loading.
Note: -
There is a bit of detail that we might be interested in this area. For example,
ClassNotFoundException. So, ClassNotFoundException happens when the class loader
fails to find the bytecode corresponding to a class we mentioned. It's as simple as that and
there is another type of exception called ClassDefNotFound, ClassDefNotFound generally
happens during a resolve phase where you try to suppose I'm loading a class X. And suppose
we went through this loading phase, and we went to the link phase, it went through the verify
because X's bytecode looks pretty good, and X is prepared. Now, suppose X is referring to
another class called Y at the resolve phase, the system tries to find out class Y because X is
referring to Y. So, if class Y cannot be found, an exception will be thrown called
ClassDefNotFound for X, which wraps ClassNotFoundException for Y. So those are some
certain exceptions that are attached to the class loading. So now we talked about class loader
subsystem and its phases.
Method Area
First is the Method Area. The method area is the place where class data, the metadata
corresponding to class is stored. A lot of APIs in Java reflection API for class, the class
class, inquires data in the method area.
So, you have the static variables, you have the bytecode, you have the class level constant
pool. everything is stored in the method area.
So, method area is basically, you know, is the memory allocated to the JVM. It is created
when the JVM starts, and it is destroyed only when the JVM exits.
So, the method area is called the permgen space. So, the permgen space is the place by
default, 64 megabytes, 64 MB is allocated for method area or permgen. So, this can be
tuned. Suppose your application is a huge server application that loads a lot of classes,
millions of classes. In that case, you will have to tune the permgen using XX:
MaxPermSize and you can set it to a certain MB or GB as you might need it. Right. So,
suppose your application has the permgen is very, very low corresponding. Suppose
you're trying to load a million classes, but you never talked about MaxPermSize. I
suppose you left it at 64 MB. So, your application might run into
Java.lang.OutOfMemoryError for permgen space.
So, since Java 8, they have gotten rid of the method area or the permgen, which is called
now the metaspace in Java 8. So, what they've done is moved the permgen or method
area into a separate memory in the native operating system and that is called the
metaspace. So, the point is, by default, there is no limit to metaspace in Java 8. So, you
can just grow as long as it can grow based on the operating system. It can just go grow
and occupy full memory or it can go to the virtual memory and things like that. So that's
the difference between permgen and metaspace and metaspace again can be tuned, can be
limited. Suppose you don't want it to just grow. You can limit using a certain JVM
parameter that you can check out on the Java 8 JVM Java command options.
Heap
Now coming over to the next runtime data area, which is Heap. Heap is a very popular
memory area in JVM, and you would have come across a lot of things to do with heap,
like OutOfMemoryError for heap, etc. A lot of people might have seen in their life.
So, heap is a place where object data is stored. So, every time you instantiate an object,
suppose you recall something like MyApp app=new MyApp, that object is created in the
heap. So, anything to do with object is created in the heap.
So, all the instance variables, arrays, everything is since arrays are objects are created in
heap. So, heap is a very important memory area in Java.
That most of the time needs to be tuned based on your application requirements. So that
is tuned using minus -Xms for the minimum size and minus -Xmx for the maximum size.
So, you can tune it using your parameters and adjust it as the application needs.
PC Registers
PC register is basically program counter registers. So, it contains program counter, which
is the pointer to the next instruction to be executed Per thread. So, suppose in this case,
we are running 3 threads T1, T2 and T3. So, there will be program counter created for T1
pointing to the next instruction for thread one T2 pointing to the next instruction for T2
and T3 pointing to the next instruction for T3. All these three will be created in the
program counter registers. So, that is per thread.
Now Java stacks. Java stacks contains stack frame corresponding to the current method
execution per thread. Suppose we have a thread that is executing 3 methods. So, the Java
stack for that thread, this is T1 in this case, this is T2, and this is T3. So, T1 has three
method executing currently so it would have pushed. Suppose this method calls this
method and this method. So, it will have pushed first stack frame corresponding to first
method. Suppose method one is called method two. So, it would push the stack frame
corresponding to method two into the stack. Suppose this method two is called method
three. So, it'd push the stack frame corresponding to method three into the stack. So, and
it'll be popped based on how it is returning, So, this is per thread and stack frame
basically contains data related to the currently executing method.
suppose one of our method is invoking a native method. So that's why that's the point
when native methods stack come into picture. So, at that point of time, a native method
stack will be created for that native method that you're calling.
Stack basically is per method invocation, as I said, the stack frames. So, let's think about a
recursive algorithm and, you know, recursive methods, as you know are the method that
call itself for example factorial. So, the recursive method calls itself. Suppose we forgot
to put the exit condition or they call it the basic condition of the recursion so that it can be
returned. Right. Suppose we forgot to mention the exit criteria for recursion. So, what
happens? Your method calls itself infinitely. So as a result, what will happen? Stack
frame for each invocation will be pushed into this stack. So, you know, it will keep on
adding stack frame over stack frame or stack frame over stack frame. And as a result,
what will happen is this memory area, this data area will run out of memory and when
that happens, you will get this exception called Java.lang.stackoverflow Error.
whenever the stack overflow error happens, you have to look for some recursive type
calls that are going to push, keep on pushing stack frames and never popping them, never
returning out of co-ops. So, you would have to look for that type of scenario to resolve
that issue and maybe there are certain genuine cases where you might have to tune your
Java stacks. So, in that case, what you would use is the -Xss parameter as shown here.
Execution Engine
Now let's go to the final point, which is the execution engine. So once. The data area is loaded with
the instruction to be executed. What happens is that the Java interpreter interprets the current
instruction that is there in the bytecode and executes it. So, the execution engine, you know, in a
broad sense, has the following components that is interpreter. Then there is JIT compiler, just in time
compiler, hotspot profiler and garbage collector.
Compiler VS Interpreter
Compiler Interpreter
o It scans the entire programs first and translates it o It scans the program line-by-line and translates it
into machine code. into machine code.
o Compiler shows all errors & warning at same o Interpreter shows one error at a time.
time.
o Error occurs after scanning the whole programs. o Error occurs after scanning each line.
o Debugging is slow bcz if error occurs we don’t o Debugging is faster.
know at which line error occur.
o Execution time is less. o Execution time is more.
o Compiler is used by language such as c, c++ etc. o An Interpreter is used by language such as java,
python etc.
JIT Compiler
JIT stands for Just-In-Time Compiler. JIT is a part of JVM.
The actual use of JIT is to compile the bytecode to machine code at a runtime. JIT converts the
bytecode into a machine code at a runtime and performs some optimization on code so that
code can be executed very fast and improve the performance of execution at the runtime if
some program contains one instruction or a method which can be executed more than a
thousand times. At that time, in traditional JVM, the JVM used to read the instructions and
convert that instruction into a machine code and execute that instruction on a CPU. Every time
that instruction occurs, it is converting into a machine code and then it is executed on a
machine. But it is time-consuming. Every time it needs to convert it into a machine code.
So, Java developer finds some solution and implemented a JIT compiler. So, what JIT compiler
will do? The JIT compiler will check at the runtime that which instruction is executing multiple
times. It will compile that instruction and keep it into a memory so that next time the same
instruction or method occurs, it will pick the method from that memory and no need to
recompile that method or convert that method into a machine code. So, ultimately, this will
improve the execution time of a program.
also, the JIT compiler has some inbuilt optimization methods so that it looks for a code that it
checks if some code has some part of code or instruction that are not used, or they are just
written badly. That is some expression is written but we are not using that instruction and we
are just assigning like we have some instruction like A=A+B and we are not using the result of A
or displaying the result of A anywhere. So, what JIT will do? JIT will eliminate this instruction and
it will not compile the instruction at a runtime so that it will ultimately increase the performance
of execution. This is how the JIT will improve the Java performance of execution.
Summary:
So, first is the class loader subsystem. Second is the runtime data areas. Third is the execution engine and class
loader subsystem have load, link, initialize and load is for the class loaders. Link has three different steps. You
can go into details later and initialize initializes runs the static initializes and the runtime data area, you have
five different data areas, which is basically the memory space allocated for JVM, which is method area for class
data heap for object data. Java stack per thread keeps track of currently executing method and its data and PC
registers per thread, the program counters that knows what execution, what operation to execute next and
native methods stacks corresponding to native methods used by the application and execution engine. We
saw as the interpreter just in time compiler, compiler, hotspot profiler, which is sometimes they call it the
hotspot VM. Then you have the garbage collector, which interfaces with the native libraries through native
method interfaces. That summarizes the JVM architecture.
Garbage Collection in Java
How garbage collection works in Java and what are the garbage collectors are there and what are the purpose of
those and how to use them.
o Java provides automatic memory management through a program/thread called garbage collector
o live object = reachable (referenced by another object or someone else in your Application)
o dead object = unreachable (not referenced from anywhere)
o Objects are allocated in the heap of Java memory. So, there is a heap memory in Java where new whenever
you call a new and allocate object that is allocated in the heap also arrays are object in Java, so they are also
allocated in heap.
o Static members, class definitions, class metadata etc are stored in method area of the JVM which is
basically the permgen or the metaspace in modern Java versions like Java 8.
o Garbage collection is carried out by a daemon thread called garbage collector.
o We can’t force GC to happen using (System.gc()).
o When new allocation can’t happens due to a full heap you end up with a Java.lang.OutOfMemoryError
heap space . so, indicating you are no longer able to use heap anymore because it's full and that is a time
when you will probably start looking for objects leaks or memory leaks in your program.
o
- Mark:- Garbage collection basically involves 3 steps which is mark and sweep and compacting. So, mark is
basically a step where the garbage collector walks through the object graph which I talked about which is
basically will have a root node of your application. Suppose you have a class called application which got
invoked at the beginning and everything gets created from there so that is the root node and from that root
node you have references to some other objects and all of them refers to something else so it's like a big graph
in memory. So, the garbage collector walks that graph and visits each node and marks whichever object is
reachable as reachable and whichever object is not reachable it just leaves alone and moves forward.
-Sweep:- So next step is deleting or sweeping so as a name indicates is the step where things are cleared off.
So, whichever is marked as reachable is not touched and whichever is not reachable the garbage collector
thread would just clean them or sweep them off from the heap and thus reclaims the memory but then comes
the step of compacting.
-Compacting:- So compacting is the process where you try to arrange everything in order. So, suppose we have
heap here so let's assume heap like a big grid of something and from in the grid you could have unreachable
object here. So, you keep on cleaning them off then there are holes in the whole heap right. So, there are so
suppose you don’t have contiguous allocation suppose here allocation has happened here you have removed
something which is unreachable then again, some reachable objects. So, to avoid this fragmentation the
compaction is done. So, all the objects are arranged in order so that you know free memory is at the end of the
heap. So that is basically compaction and if you have used the disk defragment tool that comes with Windows
you would have seen a graphic representation of how the disk files and the disk blocks which are non-
contiguous how it makes contiguous. So, you would have seen that so it's similar to that the compacting step
and as you can imagine that's a time-taking step because it has to go through the entire heap and then arrange
to the allocated space accordingly. So we'll come to that details very shortly so let's proceed and see what are
the generations in Java heap.
Generational Collectors
So basically, Java garbage collectors are called generational collectors because it depends on the generation of
your objects meaning if the object is young or if the object is old or did the object survive how many cycles of
garbage collection and things like that. So, as you can see in this diagram the heap is divided into two spaces
one is young generation space and the other one is old or tenured generation space. So, the young generation as
you can see is the place where objects are created initially. So young generation as the name indicates is for
young objects where the new objects are created, and young generation is further divided into Eden space. Eden
is a place where new things are created actually whenever you call something like new say hash map for
example that hash map objects is created in the Eden space and it's called Eden because it's a reference to the
theory of Genesis in Bible where according to the books the life was first created in garden of Eden so they just
used that name so it's called Eden space where new objects are created. So, there are then survivor space that
means suppose objects are allocated in the Eden space and the Eden space becomes full that means whenever
you call something like new hash map next time you don't have any more Eden space to create that hash map.
So that is the time small garbage collection kicks in and cleans up the Eden space of all unreachable objects and
all reachable object it moves on to the survivor space indicating it survived a garbage collection. So, then Eden
becomes free and again you can happily allocate new objects there. So, there are other purpose of why there are
two survivor spaces we will soon see that. So that is the division of young generation into three spaces.
Then you have old generation which holds objects that survives for a long time are promoted into old
generation. Suppose you created a cache in your application which is supposed to stay there for the entire
applications life. So suppose initially when you created your cache it's created in the Eden space and then it's
moved to survivor space and after a few generations of garbage collection suppose it survives a lot of cycles of
garbage collection that cache object will be moved to old generation where it stays and if it is never unreachable
it just stays forever and if it ever becomes unreachable it gets collected by a major garbage collection which
actually runs garbage collection steps all throughout the heap.
So, in this slide we saw a couple of very important points
o one is the division of heap into young and old generation and another one is
o minor garbage collections that run in the young generation and major garbage collection that runs across the
heap.
o at the same time, you should be aware that any steps of garbage collection minor or major they are called
stop the world garbage collection. So both are stop the world only thing is that minor is running on a very
small a short amount of memory and so it's not that you know intrusive you won't feel that the application is
stopping or something but when the major garbage collection kicks in it has to run from the entire heap
from one end to the other and do the mark sweep and compacting of the whole objects so that would really
cause a pause in your application for about seconds which would be really undesirable. So those are some
points that we should keep in our mind from this slide.
So in this animation what I'm going to show is how the Eden space minor garbage collections happen and also you
should be aware that this slide is only showing the young generation it's not showing the old generation okay so here I
have the Eden space where objects are created and here I have the survivor from space and survivor to space so as
the application your application runs new objects get allocated in the Eden space and when the application runs there
are objects that become unreachable I'm marking them as Gray here and then now the Eden space is kind of full so at
this point when your application tries to create another objects and JVM tries to allocate something on the Eden the
allocation fails and that actually causes one minor GC to run and when minor GC runs at the end of it it has marked all
the live objects as reachable and those are moved into the survivor space.
So, when they are moved into survivor space the unreachable objects are sweeped and cleaned up and we are good.
So this slide indicates the after first cycle of garbage collection what just happened you have you know all the objects
that survived one cycle of garbage collection in the survivor space and they are all have a counter it says okay it
survived one cycle of garbage collection now again the application goes and allocates objects in the heap and along
the way some things in the survivor space becomes unreachable and more objects are allocated some objects are
again becoming unreachable and stuff like that and at this point the heap is the Eden of the heap is full and there are
some unreachable objects here and there are new objects reachable objects here reachable out objects are still here
so at this point JVM tries to allocate yet another object and it fails and
when the allocation fails it triggers yet another minor GC and at the end of that minor GC all the reachable objects are
marked as still as reachable across the Eden and survivor and then they are all moved to the survivor 2 as you can see
they are moved to the survivor space 2 and objects from survivor 1 is also moved into survivor 2 okay so this is how
that movement happens and now clean-up of these unreachable objects are done and all the reachable objects are
now in survivor 2 like this so this indicates okay there are these objects that survive two cycles of garbage collection
and these objects that survives one cycle of garbage collection
so you might wonder why there is this multiple survivor space in heap so the reason is because to avoid another run
of compacting step so as you can see when the movement happens they are arranged in sequential order like a
contiguous order so this actually avoids the need to run another compacting step that will be expensive but instead
since you have to anyway move around the objects you are just moving it away and ordering it one after other and
avoiding the compacting step so that is the purpose of the survivor spaces and now let's see what happens in the heap
again new objects are created in the heap some things are becoming unreachable these are again here these are
becoming unreachable and then you keep JVM keeps on allocating your objects whenever needed and there are a lot
of unreachable objects now in Eden as well as the survivor and the Eden is sort of full now and now you try to allocate
one more objects and that allocation fails and at this point one more minor GC gets triggered and as a result all the
reachable objects are moved to survivor 1 so things are now moving back to survivor 1 from survivor 2 as you can see
so at the end of this all the unreachable objects are cleaned up
so there are some things that you should be aware of that you know the minor GC is very short because it's running
quickly over the Eden space and the survivor space and at the end of that cycle objects are moved into the survivor
space from one survivor to another and then from there back to the previous survivor and this you know reordering
continues until a threshold number say 16 let's take 16 as the example and at the end of that threshold what will
happen is whatever is survived for example see here the counter has incremented indicating these objects survived
one cycle of garbage collection this survived two cycles of garbage collection and this survived three collections of
three cycles of garbage collection so
when the threshold is hit saying okay if any object is has survived say 16 cycles of garbage collections they are
promoted to the next generation which is old generation indicating okay these are objects that are really not going
away they are going to stay here for a while so they are moved to old generation as you can see in this diagram so
that is based on a max tenuring threshold and all the objects that are living long in survivor or Eden they are moved
out into old generation and there is some breathing space again back in the young generation so those are the basic
functionality of garbage collector and how it is implemented
so what happens when old generation gets full so there is this garbage collect thread that keeps on watching old
generation sees oh my god my old generation is almost full now I'm soon going to be in trouble so at that point of
time the major garbage collection kicks in which goes over all the generations and performs mark sweep and
compacting which is you know three of these steps it has to perform and it has to perform across the heap suppose
your heap size is say 8 GB or 16 GB it has run across the whole 8 GB allocated for JVM and hence it can be a very time-
consuming operation causing your application to halt literally okay so as you can see a lot of minor garbage
collections runs in the background on the young generation which are quick so it doesn't appear to be really pausing
your application but the major generation which is going to run through the entire heap would cause your application
to pause.
Let's talk about performance with relation to garbage collection so in performance we have to be aware of two terms okay
so one is responsiveness or latency and the second one is throughput.
Performance
- Responsiveness/Latency
- Throughput
Throughput focus on maximizing the amount of work by an application in a specific period of time. Example of how
throughput might be measured include:
- The number of transactions completed in a given time.
- The number of jobs that a batch program can complete in an hour.
- The number of database queries that can be completed in an hour.
- High pause times are acceptable for applications that focus on throughput. since high throughput
applications focus on benchmarks over longer periods of time, quick response time is not consideration.
1. A serial Collector
A very Basic Garbage Collector that runs in a Single Thread.
you know the that means your application will be running suddenly it's paused and a single
thread of garbage collection of mark sweep and compacting runs again your application runs
again paused and a single thread of your mark sweep and compacting is done so that is a
serial collector.
2. A Concurrent Collector
A thread that performs garbage collection along with the application so that means as the
application runs this concurrent thread of garbage collection also runs.
Doesn’t wait for the old generation to be full. (It does not wait for the old generation to be full so it
keeps on running and whenever it can it can do certain sweeping compacting happens in parallel with the
application so that is why it is called the concurrent collector)
Stops the world only during mark/re-mark.
3. A Parallel Collector
Uses multiple CPUs to perform GC
Multiple Threads do mark/sweep etc.
Doesn’t kick in until heap is full or near full.
“stop-the-world” when it runs.
Answer.
1) Static variables/ fields are not garbage collected and can cause memory leak in java >
Static variables are only garbage collected when the class loader which has loaded the class in which static field
is there is garbage collected.
So, be cautious as these static variables can create a memory leak in java.
5) Using custom key in map without Overriding equals () and hashCode() method can cause memory leak >
If custom key is used and equals() and hashCode() method are not overridden then, key will not be retrieved
by using get() method.
Because get () method internally calls equals () and hashCode () method for retrieving keys.
So, these keys will neither be used nor be garbage collected, so it’s a clear case of memory leak.
So, to avoid memory leak while using custom key you must always Override equals () and hashCode() method
Learn how you can use custom key (Employee object) in custom HashMap Custom implementation - put, get,
remove So, to avoid memory leak you must try use String, Integer, Long, Double, Float, Short and any other
wrapper class as key in HashMap.
7) Memory leaks can also be caused by native methods in java > Memory allocated through native methods
can cause some serious memory leak.
8) Memory leak in web applications in java
Unused Objects stored in application scope are memory leak because they are not collected until web
application is stopped.
Is there any difference between creating string with and without new operator?
When String is created without new operator, it will be created in string pool.
When String is created using new operator, it will force JVM to create new string in heap (not in string pool).
Let’s discuss step-by-step what will happen when below 5 statements will be executed >
String s1 = "abc";
String s2 = new String("abc");
String s3 = "abc";
String s4 = new String("abc");
String s5 = new String("abc").intern();
String s1 = "abc";
No string with “abc” is there in pool, so JVM will create string in string pool and s1 will be a reference variable which will
refer to it.
String s3 = "abc";
string with “abc” is there in pool, so s3 will be a reference variable which will refer to “abc” in string pool.
1. Final memberVariable/instanceVariable of class must be initialized at time of declaration, once initialized final
memberVariable cannot be assigned a new value.
2. Final method cannot be overridden, any attempt to do so will cause compilation error.
Runtime polymorphism is not applicable on final methods because they cannot be overridden.
3. Final class cannot be extended, any attempt to do so will cause compilation error.
1) Final variable - once initialized final memberVariable cannot be assigned a new value in java
Final memberVariable/instanceVariable of class must be initialized at time of declaration, once initialized final
memberVariable cannot be assigned a new value in java.
class FinalTest {
final int x=1; //final memberVariable/instanceVariable
}
If final memberVariable is not declared at time of declaration we will face compilation error= “The blank final field x may
not have been initialized”’.
If final memberVariable is assigned a new value we will face compilation error=”The final field FinalTest.x cannot be
assigned ”.
If constructor is defined then final memberVariable can be initialized in constructor but once initialized cannot be assigned a
new value.
class FinalTest {
final int x; //final memberVariable/instanceVariable
FinalTest() {
x = 1; //final memberVariable can be initialized in constructor.
}
}
Final local variable can be left uninitialized at time of declaration and can be initialized later, but once initialized cannot be
assigned a new value in java.
class FinalTest {
void method(){
final int x; //final variable uninitialized at time of declaration
x=1;
}
}
Final static variable of class must be initialized at time of declaration or can be initialized in static block, once initialized
final static variable cannot be assigned a new value.
If static block is defined then final static variable can be initialized in static block, once initialized final static variable cannot
be assigned a new value in java.
class FinalTest {
final static int x; //final static variable
static{ //static block
x=1;
}
}
So, in short using final with variable means that it cannot be assigned a new value in java.
Final method cannot be overridden, any attempt to do so will cause compilation error.
Runtime polymorphism is not applicable on final methods because they cannot be inherited.
So, in short using final with method means that it cannot be inherited in java.
So, in short using final with class means that it cannot be extended in java.
3. Final memberVariable/instanceVariable of class must be initialized at time of declaration, once initialized final
memberVariable cannot be assigned a new value.
class FinalTest {
final int x=1; //memberVariable/instanceVariable
}
4. If final memberVariable is not declared at time of declaration we will face compilation error= “The blank final
field x may not have been initialized”’.
5. If final memberVariable is assigned a new value we will face compilation error=”The final field FinalTest.x cannot
be assigned ”.
6. If constructor is defined then final memberVariable can be initialized in constructor but once initialized cannot be
assigned a new value.
class FinalTest {
final int x; //memberVariable/instanceVariable
FinalTest() {
x = 1; //final memberVariable can be initialized in constructor.
}
}
7. Final local variable can be left uninitialized at time of declaration and can be initialized later, but once initialized
cannot be assigned a new value.
class FinalTest {
void method(){
final int x; //uninitialized at time of declaration
x=1;
}
}
8. Final static variable of class must be initialized at time of declaration or can be initialized in static block, once
initialized final static variable cannot be assigned a new value in java.
variables in interface are public, static and final by default. Interface variables are also known as constants.
10. If static block is defined then final static variable can be initialized in static block, once initialized final static
variable cannot be assigned a new value in java.
class FinalTest {
final static int x; //static variable
static{ //static block
x=1;
}
}
11. Final method cannot be overridden, any attempt to do so will cause compilation error in java.
Runtime polymorphism is not applicable on final methods because they cannot be overridden.
class Superclass {
final void superclassFinalMethod(){
System.out.println("in Superclass final method");
}
}
class Subclass extends Superclass{
void subclassmethod(){
System.out.println("in sub class method");
}
}
public class FinalTest {
public static void main(String[] args) {
Subclass obj=new Subclass();
obj.superclassFinalMethod();
}
}
/*OUTPUT
in Superclass final method
*/
13. Final class cannot be extended, any attempt to do so will cause compilation error in java.
14. Constructor of a class can never be final in java - because they are not inherited neither overridable.
Only public, protected & private are permitted modifiers with constructor.
,any attempt to make constructor final will cause compilation error=”Illegal modifier for the constructor in type FinalTest;
only public, protected & private are permitted” in java.
15. There is nothing like final object in java - if final reference variable refers to object in java than it does not mean
that Object is final, it simply means that reference variable cannot refer to another object in java.
16. final list does not means that - value cannot be added to it or removed from list.
final list means reference cannot refer to any new ArrayList, any attempt to do so will cause compilation error in java.
17. If parameter is final its value cannot be changed, any attempt to do so will cause compilation error in java.
18. Final class can never be abstract, because final class cannot be extended and abstract class is meant for
extending
any attempt to do so will cause compilation error in java.
19. declaring variable, class or method as final improves performance, because JVM caches them. JVM caches them
because -
a. final variable cannot be changed in java,
b. Runtime polymorphism is not applicable on final methods because they cannot be overridden in java.
c. final classes cannot be inherited in java.
20. As per java naming conventions final variable must be written in UPPERCASE because they are considered as
constants in java.
21. Only final local variable can be used inside an inner class defined in a method.
Though non-final member variable can be used inside an inner class defined in a method.
class MyClass{}
class MainClass {
int memberVar=0; //member variable
void m(){
final int localVar=0; //final local variable
MyClass myClass=new MyClass(){
void m(){
System.out.println(localVar);
System.out.println(memberVar);
}
};
}
}
Using non-final local variable inside an inner class will produce compilation error =”Cannot refer to a non-final variable
localVar inside an inner class defined in a different method” in java.
For using object as Key in HashMap, we must implements equals and hashcode method.
Classes must be made immutable classes.
@Override
public int hashCode(){
int hash=(this.id==null ? 0: this.id.hashCode() ) +
(this.name==null ? 0: this.name.hashCode() );
return hash;
}
Let’s say in an organisation there exists a employee with id=1 and name=’sam’ and some data is stored corresponding to
him, but if modifications have to be made in data, previous data must be overridden.
@Override
public int hashCode(){
int hash=(this.id==null ? 0: this.id.hashCode() ) +
(this.name==null ? 0: this.name.hashCode() );
return hash;
}
}
public class EmployeeOverride {
public static void main(String...a){
HashMap<Employee, String> hm=new HashMap<Employee, String>();
hm.put(new Employee(1,"sam"), "employee1 data");
hm.put(new Employee(2,"amy"), "employee2 data");
System.out.println("HashMap's data> "+hm);
System.out.println(hm.get(new Employee(1,"sam")));
hm.put(new Employee(1,"sam"), "employee1 data OVERRIDDEN");
System.out.println("\nAgain display HashMap after overriding data "+
"of Employee with id=1 and name=’sam’\n");
System.out.println("HashMap's data> "+hm);
System.out.println(hm.get(new Employee(1,"sam")));
}
}
/*OUTPUT
HashMap's data> {Employee[id=1, name=sam] =employee1 data, Employee[id=2, name=amy] =employee2 data}
employee1 data
Again display HashMap after overriding data of Employee with id=1 and name=’sam’
HashMap's data> {Employee[id=1, name=sam] =employee1 data OVERRIDDEN, Employee[id=2, name=amy]
=employee2 data}
employee1 data OVERRIDDEN
*/
If we note output >
Earlier, value corresponding to Employee with id=1 and name=’sam’ was employee1 data
Later, value corresponding to Employee with id=1 and name=’sam’ was employee1 data OVERRIDDEN
2) private member variable -> Making member variables private ensures that fields cannot be accessed outside class.
3) final member variable -> Make member variables final so that they can be assigned only once.
6) object of immutable class - Any change made to object of immutable class produces new object.
object of mutable class - Any change made to object of mutable class doesn't produces new object.
- Integer, String are immutable class,
any changes made to object of these classes produces new object.
so return reference variable of Integer.
- HashMap is mutable class,
any changes made to HashMap object won't produce new HashMap object.
so return copy/clone of object, not reference variable of HashMap.*/
/**
* 2) private member variable -> Making fields private ensures that fields
cannot be accessed outside class.
* 3) final member variable -> Make field final
so that they can be assigned only once.
*/
private final Integer id; //Immutable member variable
private final String name; //Immutable member variable
private final HashMap<Integer,String> map; //mutable member variable
/** 4) Constructor -> Initialize all fields in constructor.
* assign all mutable member variable using new keyword.
*/
public ImmutableClass(Integer id, String name, HashMap<Integer,String> map){
this.id=id;
this.name=name;
//change local
localId = new Integer(2);
localName = new String("mittal");
localMap.put(12, "ferarri");
This question will check your in depth knowledge of Java’s Collection Api’s. we should prefer String, Integer, Long,
Double, Float, Short and any other wrapper class. Reason behind using them as a key is that they override equals() and
hashCode() method, we need not to write any explicit code for overriding equals() and hashCode() method.
import java.util.HashMap;
import java.util.Map;
public class StringInMap {
public static void main(String...a){
//HashMap's key=Integer class (Integer’s api has already overridden hashCode() and equals() method for us )
Map<Integer, String> hm=new HashMap<Integer, String>();
hm.put(1, "data");
hm.put(1, "data OVERRIDDEN");
System.out.println(hm.get(1));
}
}
/*OUTPUT
data OVERRIDDEN
*/
If, we note above program, what we will see is we didn’t override equals() and hashCode() method, but still we were able to
store data in HashMap, override data and retrieve data using get method.
>Let’s check in Integer’s API, how Integer class has overridden equals() and hashCode() method :
Before understanding the concept of overriding equals() and hashCode() method, we must understand what is bucket,
Entry, and Entry.next
If, hashCode() method is overridden properly, we will find bucket location using hashCode() method, we will obtain
Entry on that bucket location, then iterate over each and every Entry (by calling Entry.next) and check whether new and
existing keys are equal or not. If keys are equal replace key-value in Entry with new one, else call Entry.next But, now the
question comes how to check whether two keys are equal or not. So, it’s time to implement equals() method.
If, hashcode method is not overridden for same key every time hashCode() method is called it might produce different
hashcode, there might happen 2 cases i.e. when put and get method are called.
Case 1 : when put() method is called-
There might be possibility that same Entry (with key-value pair) will get stored at multiple locations in bucket.
Conclusion> key- value pair may get stored multiple times in HashMap.
Case 2 : when get() method is called-
As there is possibility that hashCode() method might return different hashcode & rather than searching on bucket location
where Entry(with key) exists we might be searching for key on some other bucket location.
Conclusion> key existed in HashMap, but still we were not able to locate the bucket location in which it was stored.
If equals method is not overridden - though we will be able to find out correct bucket location if hashCode() method is
overridden correctly, but still if equals method is not overridden, there might happen 2 cases i.e. when put and get method
are called.
Case 1 : when put() method is called-
we might end up storing new Entry (with new key-value pair) multiple times on same bucket location (because of absence of
equals method, we don’t have any way of comparing key’s),
In this case, even if keys are equal, we will keep on calling Entry.next until we reach last Entry on that bucket location and
ultimately we will end up storing new Entry (with new key) again in same bucket location.
Conclusion> key- value pair stored multiple times in HashMap.
Case 2 : when get() method is called-
we won’t be able to compare two keys (new key with existing Entry.key) and we will call Entry.next and again we won’t
be able to compare two keys and ultimately when Entry.next is null - we will return false.
Conclusion> key existed in HashMap, but still we were not able to retrieve it.
So, it’s important to override equals method to check equality of two keys.
If two objects equals() method return true, do objects always have same hashcode?
Answer. Yes, two objects can return true only if they are stored on same bucket location.
First, hashCode() method must have returned same hashcode for both objects, then on that bucket location’s Entry
key.equals() is called, which returns true to confirm objects/keys are equal.
So, if object’s equals return true, they always have same hashcode.
What is difference between using instanceOf operator and getClass() in equals method?
Answer. If we use instanceOf it will return true for comparing current class with its subclass as well,
but getClass() will return true only if exactly same class is compared. Comparison with any subclass will return false.
Interviewers sometimes tend to confuse interviewees by framing different question by overriding either of equals() or
hashCode() method. Interviewers aims to check in depth knowledge of interviewees that how many buckets are formed,
what is sizeOf HashMap after each experiment and get() method returns object or not (Important).
How many buckets will be there and what will be size of HashMap?
package p1;
import java.util.HashMap;
class Employee {
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
public class Program1 {
public static void main(String...a){
}
}
Answer.
/*OUTPUT
HashMap's data> {Employee[ name=a] =emp1 OVERRIDDEN, Employee[ name=a] =emp1, Employee[ name=b] =emp2}
HashMap's size> 3
null
*/
Buckets= As hashCode() method is not there, hashcode generated for 3 objects will be different and we will end up using 3
buckets.
Size= As equals() method is not their, size will be 3.
get()=we won’t be able to get object.
How many buckets will be there and what will be size of HashMap?
package p2;
import java.util.HashMap;
class Employee {
@Override
public int hashCode(){
return (this.name==null ? 0: this.name.hashCode() );
}
@Override
public boolean equals(Object obj){
Employee emp=(Employee)obj;
return (emp.name==this.name || emp.name.equals(this.name));
}
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
public class Program2 {
public static void main(String...a){
}
}
Answer.
/*OUTPUT
HashMap's data> {Employee[ name=b] =emp2, Employee[ name=a] =emp1 OVERRIDDEN}
HashMap's size> 2
emp1 OVERRIDDEN
*/
Buckets= As hashCode() method is overridden perfectly, 2 bucket locations will be used.
Size= As equals() method is their, size will be 2,
value corresponding to Employee with id=1 and name=’sam’ was employee1 data
& was overridden by value employee1 data OVERRIDDEN
get()=we will be able to get object.
How many buckets will be there and what will be size of HashMap?
package p3;
import java.util.HashMap;
class Employee {
@Override
public int hashCode(){
return 1;
}
@Override
public boolean equals(Object obj){
return true;
}
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
public class Program3 {
public static void main(String...a){
How many buckets will be there and what will be size of HashMap?
package p4;
import java.util.HashMap;
class Employee {
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
public class Program4 {
public static void main(String...a){
}
}
Answer.
/*OUTPUT
HashMap's data> {Employee[ name=a] =emp1 OVERRIDDEN, Employee[ name=b] =emp2, Employee[ name=a] =emp1}
HashMap's size> 3
null
*/
Buckets= As hashCode() method returns 1, only 1 bucket location will be used.
Size= As equals() method doesn’t exist, size will be 3, all three employees will be stored on same bucket location but in
different Entry.
get()=we won’t be able to get object.
How many buckets will be there and what will be size of HashMap?
package p5;
import java.util.HashMap;
class Employee {
@Override
public boolean equals(Object obj){
return true;
}
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
public class Program5 {
public static void main(String...a){
}
}
Answer.
/*OUTPUT
HashMap's data> {Employee[ name=b] =emp2, Employee[ name=a] =emp1 OVERRIDDEN, Employee[ name=a] =emp1}
HashMap's size> 3
null
*/
Buckets= As hashCode() method is not there, hashcode generated for 3 objects will be different and we will end up using 3
buckets.
Size= Though equals() method is their(but because of hashCode() method’s absence) which always returns true, we won’t
be able to locate correct bucket location for calling equals() method, so, size will be 3.
get()=we won’t be able to get object.
How many buckets will be there and what will be size of HashMap?
package p6;
import java.util.HashMap;
class Employee {
@Override
public int hashCode(){
return (this.name==null ? 0: this.name.hashCode() );
}
//no equals() method
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
public class Program6 {
public static void main(String...a){
}
}
Answer.
/*OUTPUT
HashMap's data> {Employee[ name=b] =emp2, Employee[ name=a] =emp1 OVERRIDDEN, Employee[ name=a] =emp1}
HashMap's size> 3
null
*/
Buckets= As hashCode() method is overridden perfectly, 2 bucket locations will be used.
Size= As equals() method is not their, size will be 3,
get()=we won’t be able to get object.
How many buckets will be there and what will be size of HashMap?
package p7;
import java.util.HashMap;
class Employee {
@Override
public boolean equals(Object obj){
Employee emp=(Employee)obj;
return (emp.name==this.name || emp.name.equals(this.name));
}
@Override
public String toString() {
return "Employee[ name=" + name + "] ";
}
}
}
}
Answer.
/*OUTPUT
HashMap's data> {Employee[ name=a] =emp1, Employee[ name=a] =emp1 OVERRIDDEN, Employee[ name=b] =emp2}
HashMap's size> 3
null
*/
Buckets= As hashCode() method is not there, hashcode generated for 3 objects will be different and we will end up using 3
buckets.
Size= Though equals() method is their(but because of hashCode() method’s absence), we won’t be able to locate correct
bucket location for calling equals() method, so, size will be 3.
get()=we won’t be able to get object.
We will calculate hash by using our hash(K key) method - in this case it returns
key/capacity= 30%4= 2.
So, 2 will be the index of bucket on which newEntry object will be stored.
We will go to 2nd index as it is pointing to null we will put our newEntry object there.
At completion of this step, our HashMap will look like this-
CopyOnWriteArrayList
CopyOnWriteArraySet
ConcurrentSkipListSet
Iterator returned by few Collection framework Classes are fail-safe, means any structural modification made to these classes
during iteration won’t throw any Exception in java.
SECTION 1 (FAIL-FAST) :
Iterator returned by ArrayList are fail-fast, means any structural modification made to ArrayList during iteration will throw
ConcurrentModificationException in java.
Example/Program to show structural modification made to ArrayList during iteration will throw
ConcurrentModificationException in java.
public class ConcurrentModificationArrayListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String str = iterator.next();
System.out.print(str+" ");
if(str.equals("b"))
list.add("b2"); //will throw ConcurrentModificationException
}
}
}
/*OUTPUT
a b Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at
com.javaMadeSoEasy.ConcurrentModificationArrayListExample.main(ConcurrentModificationArrayListExample.java:2
0)
*/
Every time iterator.next() is called it internally calls checkForComodification() to checks for any modification made to
list.
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Additionally, you may also be interested in knowing what will happen if add() and remove() methods are called
subsequently in java?
Subsequent calls made to add() and remove() methods won’t avoid ConcurrentModificationException. Because in this case
modCount will be incremented twice by 1.
Below i have attached screenshot to show you variables maintained during runtime.
Note: Program was executed in debug mode. And screenshot was taken when we entered first time in while loop. Hence
value of cursor is 0 and lastRet’s is -1.
SECTION 2 (FAIL-SAFE) :
Iterator returned by CopyOnWriteArrayList are fail-safe, means any structural modification made to
CopyOnWriteArrayList during iteration won’t throw any Exception in java.
Example/ Program to show structural modification made to CopyOnWriteArrayList during iteration won’t throw any
Exception in java.
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class ConcurrentModificationCopyOnWriteArrayListExample {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
}
}
/*OUTPUT
abc
After iteration list is : [a, b, c, b2]
*/
Below i have attached screenshot to show you variables maintained during runtime.
Note: Program was executed in debug mode. And screenshot was taken when we entered first time in while loop. Hence
value of cursor is 0.
Some important classes whose returned iterator is fail-fast, means any structural modification made to these classes during
iteration will throw ConcurrentModificationException in java >
ArrayList
LinkedList
vector
HashSet
EnumSet
LinkedHashSet
TreeSet
The iterators returned by the iterator() method of the collections returned by all three Map's “collection view methods" are
fail-fast >
map.keySet().iterator(), map.values().iterator(), map.entrySet().iterator()
HashMap
Hashtable
LinkedHashMap
TreeMap
IdentityHashMap
Some important classes whose returned iterator is fail-safe, means any structural modification made to these classes during
iteration won’t throw any Exception in java >
CopyOnWriteArrayList
CopyOnWriteArraySet
ConcurrentSkipListSet
The iterators returned by the iterator() method of the collections returned by all three Map's “collection view methods" are
fail-safe >
map.keySet().iterator(), map.values().iterator(), map.entrySet().iterator()
ConcurrentHashMap
ConcurrentSkipListMap
Does finally block always execute? Will finally block execute when System.exit is called?
finally is not executed when System.exit is called, finally block is also not executed when JVM crashes because of some
java.util.Error.
try or try-catch block can be followed by finally block >
try-finally block, or
try{
//Code to be enclosed in try-finally
block
}finally{
}
try-catch-finally block.
try{
//Code to be enclosed in try-catch-finally block
}catch(Exception e){
}finally{
}
finally block can only exist if try or try-catch block is there, finally block can’t be used alone in java.
Using only finally block will cause compilation error
finally{
//only finally block will cause compilation error
}
Programming time - we will create following programs to demonstrate finally block in java >
try{
int i=10/1;
}catch(ArithmeticException e){
System.out.println("ArithmeticException handled in catch block");
}
finally{
System.out.println("finally block executed");
}
System.out.println("code after try-catch-finally block");
}
}
/*OUTPUT
finally block executed
code after try-catch-finally block
*/
Program 2 to show finally block is executed when exception is thrown, in this case catch and finally both blocks are
executed.
package finally2;
public class ExceptionTest {
public static void main(String[] args) {
try{
int i=10/0; //will throw ArithmeticException
}catch(ArithmeticException e){
System.out.println("ArithmeticException handled in catch block");
}
finally{
System.out.println("finally block executed");
}
System.out.println("code after try-catch-finally block");
}
}
/*OUTPUT
ArithmeticException handled in catch block
finally block executed
code after try-catch-finally block
*/
Program 3 to show finally block is executed when exception is thrown and not handled properly, in this case catch blocks
does not executes, finally block executes alone.
package finally3;
public class ExceptionTest {
public static void main(String[] args) {
try{
int i=10/0; //will throw ArithmeticException
}catch(IndexOutOfBoundsException e){
System.out.println("IndexOutOfBoundsException handled in catch block");
}
finally{
System.out.println("finally block executed");
}
System.out.println("code after try-catch-finally block");
}
}
/*OUTPUT
finally block executed
Exception in thread "main" java.lang.ArithmeticException: / by zero
at finally3.ExceptionTest.main(ExceptionTest.java:7)
*/
It’s important to note in above program that finally block was executed but catch block didn’t because Exception wasn’t
handled properly in above program - program throwed ArithmeticException but we were handing
IndexOutOfBoundsException.
Also, sysout statement after try-catch-finally block wasn’t executed.
Program 5 to show what will happen when catch and finally both return some value.
When catch and finally block both return value, method will ultimately return value returned by finally block
irrespective of value returned by catch block.
}
}
/*OUTPUT
method return -> finally
*/
In above program, i=10/0 will throw ArithmeticException and enter catch block to return "catch", but ultimately control will
enter finally block to return "finally".
When try and finally block both return value, method will ultimately return value returned by finally block irrespective
of value returned by try block.
public class ExceptionTest {
public static void main(String[] args) {
System.out.println("method return -> "+m());
}
}
}
/*OUTPUT
method return -> finally
*/
In above program, try block will "try", but ultimately control will enter finally block to return "finally".
unchecked exceptions
unchecked exceptions are also known as runtime exceptions.
Unchecked exceptions are those which need to be taken care at runtime.
1 Also known as checked exceptions are also known as unchecked exceptions are also known as
compileTime exceptions. runtime exceptions.
2 Should be Checked exceptions are those which need to Unchecked exceptions are those which need to be
solved at be taken care at compile time. taken care at runtime.
compile or
runtime?
3 Benefit/ We cannot proceed until we fix compilation Whenever runtime exception occurs execution of
Advantage issues which are most likely to happen in program is interrupted, but by handling these
program, this helps us in avoiding runtime kind of exception we avoid such interruptions
problems upto lot of extent. and end up giving some meaningful message to
user.
4 Creating
custom/own
exception class UserException extends Exception { class UserException extends RuntimeException
UserException(String s) { {
super(s); UserException(String s) {
} super(s);
} }
}
By extending java.lang.Exception, we can
create checked exception. By extending java.lang.RuntimeException, we
can create unchecked exception.
6 handling If superclass method throws/declare checked If superclass method throws/declare unchecked >
checked and exception > overridden method of subclass can
unchecked overridden method of subclass can declare/throw any unchecked /RuntimeException
exception while declare/throw narrower (subclass of) checked (superclass or subclass) (As shown in Program), or
exception (As shown in Program), or
overriding overridden method of subclass cannot
superclass overridden method of subclass cannot declare/throw any checked exception (As shown in
method declare/throw broader (superclass of) checked Program),
exception (As shown in Program), or
overridden method of subclass can
declare/throw any unchecked
/RuntimeException (As shown in Program)
Which classes The class Exception and all its subclasses The class RuntimeException and all its
are which type that are not also subclasses of subclasses are unchecked exceptions.
of exception? RuntimeException are checked exceptions. Likewise,
either The class Error and all its subclasses are
checked or unchecked exceptions.
unchecked
exception?
We throw NullPointerException (unChecked exception) and didn’t handled it, no compilation error was thrown.
import java.io.FileNotFoundException;
public class ExceptionTest {
public static void main(String[] args) {
m();
System.out.println("after calling m()");
}
static void m(){
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException handled in try-catch block");
}
}
}
/*OUTPUT
FileNotFoundException handled in try-catch block
after calling m()
*/
We throwed FileNotFoundException (checked exception) by using throw keyword and handled it in try-catch block.
Program 2- Handling Exception by throwing it from m() method (using throws keyword) and handling it in try-catch block
from where call to method m() was made.
import java.io.FileNotFoundException;
public class ExceptionTest {
public static void main(String[] args) {
try {
m();
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException handled in try-catch block");
}
System.out.println("after calling m()");
}
static void m() throws FileNotFoundException{
throw new FileNotFoundException();
}
}
/*OUTPUT
FileNotFoundException handled in try-catch block
after calling m()
*/
method m() propagated exception to calling method (i.e. main method) using throws.
Program 3- Throwing Exception from m() method and then again throwing it from calling method [ i.e. main method]
Ultimately exception is not handled properly in this case, but this approach is used in many live projects (i.e. in web
applications).
package throwChecked_3_throw_throw;
import java.io.FileNotFoundException;
public class ExceptionTest {
public static void main(String[] args) throws FileNotFoundException {
m();
System.out.println("after calling m()");
}
static void m() throws FileNotFoundException{
throw new FileNotFoundException();
}
}
/*OUTPUT
Exception in thread "main" java.io.FileNotFoundException
at throwChecked_3_throw_throw.ExceptionTest.m(ExceptionTest.java:12)
at throwChecked_3_throw_throw.ExceptionTest.main(ExceptionTest.java:8)
*/
Please note that System.out.println("after calling m()") statement wasn't executed.
method m() propagated exception to calling method (i.e. main method) using throws, and main propagated exception to
JVM using throws.
Above code throws NullPointerException (unChecked exception) and didn’t handled it from where method m() was called
and no compilation error was thrown.
throws Checked exception >
We need to handle checked exception either by catching it or throwing it further, if not handled we will face
compilation error.
Program 1 - Handling Exception by throwing it from m() method (using throws keyword) and handling it in try-catch block
from where call to method m() was made.
import java.io.FileNotFoundException;
public class ExceptionTest {
public static void main(String[] args) {
try {
m();
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException handled in try-catch block");
}
System.out.println("after calling m()");
}
static void m() throws FileNotFoundException{
}
}
/*OUTPUT
after calling m()
*/
method m() propagated exception to calling method (i.e. main method) using throws.
Program 2 - Throwing Exception from m() method and then again throwing it from calling method [ i.e. main method]
Ultimately exception is not handled properly in this case, but this approach is used in many live projects (i.e. in web
applications).
import java.io.FileNotFoundException;
public class ExceptionTest {
public static void main(String[] args) throws FileNotFoundException {
m();
System.out.println("after calling m()");
}
static void m() throws FileNotFoundException{
}
}
/*OUTPUT
after calling m()
*/
method m() propagated exception to calling method (i.e. main method) using throws, and main propagated exception to
JVM using throws.
1 serious Exception does not indicate any Error indicates some serious problems that our
problem? serious problem. application should not try to catch.
2 divided into Exception are divided into checked Error are not divided further into such classifications.
checked and and unchecked exceptions.
unchecked
3 Which classes The class Exception and all its Error and its subclasses are regarded as unchecked
are which type subclasses that are not also exceptions
of exception? subclasses of RuntimeException are
either checked exceptions.
checked or
unchecked The class RuntimeException and all
exception? its subclasses are unchecked
exceptions.
Likewise,
The class Error and all its subclasses
are unchecked exceptions.
5 Why to catch or Application must catch the Exception Application must not catch the Error because they does
not to catch? because they does not cause any major cause any major threat to application.
threat to application. Example >
Let’s say errors like OutOfMemoryError and
StackOverflowError occur and are caught then JVM
might not be able to free up memory for rest of
application to execute, so it will be better if application
don’t catch these errors and is allowed to terminate.
1 throw keyword is used to throw an exception explicitly. throws keyword is used to declare an
exception.
3 throw is always followed by instanceof Exception class. throws is always followed by name of
Example > Exception class.
throw new FileNotFoundException() Example >
throws FileNotFoundException
4 throw can be used to throw only one exception at time. throws can be used to throw multiple
Example > exception at time.
throw new FileNotFoundException() Example >
throws FileNotFoundException,
NullPointerException
and many more...
5 throw cannot propagate exception to calling method. throws can propagate exception to calling
method.
Please see these programs to understand how
exception is propagated to calling method.
Program 1 - Handling Exception by throwing
it from m() method (using throws keyword)
and handling it in try-catch block from where
call to method m() was made.
Program 2 - Throwing Exception from m()
method and then again throwing it from calling
method [ i.e. main method]
Exception propagation in java - deep understanding of how checked and unchecked exceptions are propagated\
In the above program, stack is formed and an exception is first thrown from the top of the stack [ method3() ] and it remains
uncaught there, and starts coming down the stack to previous methods to method2(), then to method1(), than to main() and
it remains uncaught throughout.
exception remains uncaught even after reaching bottom of the stack [ main() ] so it is propagated to JVM and ultimately
program is terminated by throwing exception [ as shown in output ].
For propagating checked exceptions method must throw exception by using throws keyword.
Now, i’ll be explaining you how checked exception was propagated.
Let’s see step by step what happened in above program >
JVM called main method
step 1 - main called method1()
step 2 - method1 called method2()
step 3 - method2 called method3()
step 4 - method3 propagated exception to method2() using throws keyword.[because, checked exceptions are not
propagated automatically]
step 5 - method2 propagated exception to method1() using throws keyword.[because, checked exceptions are not
propagated automatically]
step 6 - method2 propagated exception to main() using throws keyword.[because, checked exceptions are not
propagated automatically]
main() propagated exception to JVM using throws keyword.[because, checked exceptions are not propagated
automatically]
4) shallow copy- If we implement Cloneable interface, we must override clone method and call super.clone() from
5) Deep copy - We need to provide custom implementation of clone method for deep copying. When the copied
object contains some other object its references are copied recursively in deep copy.
Clone is a protected method - clone method can’t be called outside class without inheritance.
3) Class must implement marker interface java.lang.Cloneable. If class doesn’t implement Cloneable than calling
4) shallow copy- If we implement Cloneable interface, we must override clone method and call super.clone() from
5) Deep copy - We need to provide custom implementation of clone method for deep copying. When the copied
object contains some other object its references are copied recursively in deep copy. When you implement deep copy be
Let’s say we want to shallow copy emp object using clone method.
In shallow copy, different object is created after cloning (i.e. clonedEmp is created from emp) but member variables keep
import java.util.*;
public class CloneShallow implements Cloneable {
private String name;
private Map<Integer, Integer> map;
public CloneShallow(String name,Map<Integer,Integer> map){
this.name=name;
this.map=map;
}
/*
* override clone method for doing shallow copy.
*/
@Override
public Object clone() {
System.out.println("Doing shallow copy");
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
public static void main(String[] args) throws CloneNotSupportedException
{
}
}
/*OUTPUT
Doing shallow copy
false
true
true
*/
Let’s say we want to deep copy emp object using clone method.
In deep copy, different object is created after cloning (i.e. clonedEmp is created from emp) , also member variables starts
package clone;
import java.util.*;
public class CloneDeep implements Cloneable {
public CloneDeep(String name, Map<Integer,Integer> map){
this.name=name;
this.map=map;
}
/*
* override clone method for doing deep copy.
*/
@Override
public CloneDeep clone(){
System.out.println("Doing deep copy");
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
Iterator<Integer> it=this.map.keySet().iterator();
while(it.hasNext()){
Integer key=it.next();
map.put(key,this.map.get(key) );
}
return cloneDetailedDeep;
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneDeep obj2=(CloneDeep)obj1.clone();
System.out.println(obj1==obj2); //false
System.out.println(obj1.name==obj2.name); //false
System.out.println(obj1.map==obj2.map); //false
}
}
/*OUTPUT
Doing deep copy
false
false
false
*/
package com.home.java;
import java.util.*;
public DeepCopy(Integer id, String name, Double salary, Map<Integer, Integer> map, int[] val) {
this.id = id;
this.name = name;
this.salary = salary;
this.map = map;
this.val = val;
}
@Override
public String toString() {
return "DeepCopy{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", map=" + map +
", val=" + Arrays.toString(val) +
'}';
}
}
package com.home.java;
import java.util.HashMap;
import java.util.Map;
After copy=====
DeepCopy{id=12345, name='kaushal', salary=7826284.111, map={1234=5678, 5556=7788, 5678=989, 1919=8871},
val=[2, 3, 1, 4, 5]}
check reference vriable. i.e both objects
either refer a same varaibles or differet variables
false
false
false
false
false
false
Jackson JSON can also be used for serializing object to JSON and read it back.
Apache commons allows you to do deep cloning
Deep cloning using Serialization and deserialization - Simply serialize object by creating object of ObjectOutputStream
and then using its writeObject method. And then deserializing the object. (As done in above program)
Deep cloning using Reflection - (As done in above program)
from emp) , also member variables starts referring to different objects (i.e. name and map).
package clone;
class Employee implements Serializable {
System.out.println(emp==deSerializedEmp); //false
System.out.println(emp.getName()==deSerializedEmp.getName()); //false
System.out.println(emp.getMap()==deSerializedEmp.getMap()); //false
Why so we use SerialVersionUID : SerialVersionUID is used to ensure that during deserialization the same class (that was used during
serialize process) is loaded.
Example: Suppose a person who is in UK and another person who is in India, both are going to perform serialization and deserialization
respectively. In this case to authenticate that the receiver who is in India is the authenticated person, JVM creates an Unique ID which is
known as SerialVersionUID.
In most of the cases, serialization and deserialization both activities are done by a single person with the same system and same location.
But in serialization, sender and receiver are not the same person i.e. the persons may be different, machine or system may be different and
location must be different then SerialVersionUID comes in the picture. In serialization, both sender and receiver should have .class file at
the time of beginning only i.e. the person who is going to do serialization and the person who is ready for deserialization should contain
same .class file at the beginning time only.
Serialization : At the time of serialization, with every object sender side JVM will save a Unique Identifier. JVM is responsible to
generate that unique ID based on the corresponding .class file which is present in the sender system.
Deserialization: At the time of deserialization, receiver side JVM will compare the unique ID associated with the Object with local class
Unique ID i.e. JVM will also create a Unique ID based on the corresponding .class file which is present in the receiver system. If both
unique ID matched then only deserialization will be performed. Otherwise we will get Runtime Exception saying InvalidClassException.
This unique Identifier is nothing but SerialVersionUID.
Problem of depending on default SerialVersionUID generated by JVM :
Both sender and receiver should use the same JVM with respect to platform and version also. Otherwise receiver unable to
deserialize because of different SerialVersionUID.
Both sender and receiver should use same .class file version. After serialization if there is any change in .class file at receiver side
then receiver unable to deserialize.
To generate SerialVersionUID internally JVM may use complex algorithm which may create performance problem.
We can solve the above problem by configuring our own SerialVersionUID. We can configure our own SerialVersionUID as follows:
// User-defined SerialVersionUID
private static final long SerialVersionUID = 10l;
int i = 10;
int j = 20;
}
Program of Sender side which is going to Serialize object:
filter_none
brightness_4
// Java program to illustrate
// implementation of User-defined
// SerialVersionUID
import java.io.*;
class Sender {
public static void main(String[] args)
{
Geeks g = new Geeks();
// Here xyz.ser is the file name where the object is
// going to serialize
FileOutputStream fos = new FileOutputStream("xyz.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(g);
}
}
Program of Receiver side which is going to deserialize
filter_none
brightness_4
It's one of the favourite question of interviewers. Intention is to test few basic core java concepts.
Static method cannot be overridden in java, any attempt to do this will not cause compilation error, but the results won’t
be same when we would have overridden non-static methods.
But why?
Overriding in Java means that the method would be called on the run time based on type of the object and not on the compile
time type of it .
But static methods are class methods access to them is always resolved during compile time only using the compile time type
information.
Accessing static method using object references is a bad practice (we must access static variable using Class Name) and just
an extra liberty given by the java designers.
EXAMPLE>
In below program access to SuperClass’s static method() is resolved during compile time only using the compile time type
information (i.e. by using SuperClass obj), means calling obj.method() is always going to invoke static method() of
SuperClass.
Assign any sub type object to reference of superclass [obj=new SubClass()] won’t have any impact on call to static method
at runtime.
Accessing static method using object references is bad practice (discussed above) and just an extra liberty given by the java
designers.
}
/*OUTPUT
superClass method
*/
If non-static methods would have been used in above program, output would have been
subClass method
Important points you must know about overriding static methods in java >
Static method cannot be overridden, any attempt to do this will not cause compilation error. (Discussed above)
Static method cannot be overridden with non-static method, any attempt to do this will cause compilation error.
Non-static method cannot be overridden with static method, any attempt to do this will cause compilation error.
No, private methods are inherited in subclass and hence cannot be overridden.
Though subclass can have same name of private method in superclass.
class A {
private final void m(){
System.out.println(1);
}
}
class B extends A {
void m(){
System.out.println(2);
}
}
Method overloading and Method overriding forms base of core java. It’s very important to differentiate between two.
Both have been used intensively in java Api’s. This is one the most prominently asked important interview question in java.
Let’s compare with method overriding 1. Method name - Have same name as of superclass method,
in java.
2. Access modifier - Must not have more restrictive modifier.
Example - public method cannot be overridden by private method.
1. Method name - same
method name.
3 Method overloading is generally done Method overriding is always done in subClass in java.
in same class but can also be done in
SubClass (See Program 3)
4 Both Static and instance method can Only instance methods can be overridden in java.
be overloaded in java.
Static methods can’t be overridden in java. (Please refer this article for
detailed analysis and explanation with program)
5 Main method can also be overloaded Main method can’t be overridden in java, because main is static method
in java (In Program 4) and static methods can’t be overridden in java (as mentioned in above
point)
6 private methods can be overloaded private methods can’t be overridden in java, because private methods are
in java. not inherited in subClass in java.
7 final methods can be overloaded in final methods can’t be overridden in java, because final methods are not
java. inherited in subClass in java.
8 Call to overloaded method is bonded Call to overridden method is bonded at runtime in java.
at compile time in java.
9 Method overloading concept is also Method overriding concept is also known as runtime time polymorphism
known as compile time in java.
polymorphism in java.
Now we will learn differences between Method overloading and Method overriding in java with program and examples.
/*
* superclass - Animal
*/
class Animals {
void food() {
System.out.println("Animal may eat flesh, grass or ....");
}
}
/*
* subclass of Animal - Lion
*/
class Lion extends Animals {
@Override
void food() {
System.out.println("Lion eat - flesh");
}
}
private
default
protected
public
i.e. private is more restricted then default and default is more restricted than protected and so on.
Example 1:
class A {
protected void method()
{
System.out.println("Hello");
}
}
Example 2:
filter_none
edit
play_arrow
brightness_4
class A {
protected void method()
{
System.out.println("Hello");
}
}
What is difference between equals method and == operator in java? And what will be output of following code
snippets?
Code snippet 1 >
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2));
System.out.println(sb1.equals(sb2));
equals method
By default equals method checks for referential equality (Class may override the method and provide different functionality)
By default if x == y returns true then equals method also returns true.
Example -
>StringBuffer class doesn’t overrides equals method of Object class. The result is true if both references are referring to same
StringBuffer object.
>String class overrides equals method of Object class and compares one string object to the other string object. The result is true if
characters in both String object appears in same order.
== operator
The == operator checks for referential equality of object, it checks whether two references are referring to same object or
not.
System.out.println(s1==s2); //false
Let’s test == operator with String Object (when two references are referring to same object) >
String s3 = "abc";
String s4 = "abc";
System.out.println(s3==s4);
//true
String s4 = "abc";
string with “abc” is there in pool, so s4 will be a reference variable which will refer to “abc” in string pool
Hence, s3 and s4 will be the two reference variables referring to same String object.
equals method
The equals method is defined in java.lang.Object class
By default equals method checks for referential equality (Class may override the method and provide different functionality)
By default if x == y returns true then equals method also returns true.
System.out.println(s1.equals(s2));
//true
Let’s test == operator and equals method with StringBuffer Object >
System.out.println(sb1==sb2); //false
Hence, sb1 and sb2 will be the two reference variables referring to different stringBuffer objects.
StringBuffer class doesn’t overrides equals method of Object class. The result is true if both references are referring to same
StringBuffer object.
StringBuffer sb1 = new
StringBuffer("abc");
StringBuffer sb2 = new
StringBuffer("abc");
System.out.println(sb1.equals(sb2)); //false
Additionally, you may enjoy few more experiments using == operator and equals method on String, here i have done few >
String s1 = "abc";
String s2 = "a" + "bc";
System.out.println(s1 == s2); // true
System.out.println(s1.equals(s2)); // true
String x1 = "abc";
String x2 = new String(new char[] { 'a', 'b', 'c' });
System.out.println(x1 == x2); // false
System.out.println(x1.equals(x2)); // true
It’s important to know String are immutable - means any modification made to Sting objects produces new String Object.
Integer >
compare new Integer with new Integer using == operator for comparison >
public class Autoboxing{
public static void main(String[] args) {
Integer i1 = new Integer(3);
Integer i2 = new Integer(3);
System.out.println(i1 == i2);
//false
}
}
/*output
false
*/
Whenever new operator is used new objects are formed.
As we know, the == operator checks for referential equality of object, it checks whether two references are referring to same object or not,
i1 == i2 will always return false.
We must prefer to use equals method for comparing Integer objects i1 and i2 (because Integer class overrides equals method and checks for
value rather than referential equality) i1.equals(i2) will return true.
public class Autoboxing_EqualsMethod{
public static void main(String[] args) {
Integer i1 = new Integer(3);
Integer i2 = new Integer(3);
System.out.println(i1.equals(i2)); // true
}
}
/*output
true
*/
Tricky part comes when we compare Integer formed without using new operator >
compare Integer with Integer (where both Integers are formed without using new operator) using == operator for comparison >
public class Autoboxing{
public static void main(String[] args) {
Integer i1 = 3; //caches Integer object
Integer i2 = 3; //returns cached Integer
object
System.out.println(i1 == i2); //true
}
}
/*output
true
*/
A cache is an area of local memory that holds a copy of frequently accessed data that is otherwise expensive to get or compute.
A. Implicitly first statement of constructor is super(), [that means by default first statement of constructor super() is called, super() calls
implicit/explicit no-arg constructor of superclass].
byte
short
char
int
long
float
boolean
Threads consumes CPU in best possible manner, hence enables multi processing. Multi threading reduces idle time of CPU
which improves performance of application.
Thread are light weight process.
A thread class belongs to java.lang package.
We can create multiple threads in java, even if we don’t create any Thread, one Thread at least do exist i.e. main thread.
Multiple threads run parallely in java.
Threads have their own stack.
Advantage of Thread : Suppose one thread needs 10 minutes to get certain task, 10 threads used at a time could complete that
task in 1 minute, because threads can run parallely.
This is very basic threading question. Threads can be created in two ways i.e. by implementing java.lang.Runnable interface or extending
java.lang.Thread class and then extending run method.
1. Thread creation by implementing java.lang.Runnable interface. We will create object of class which implements Runnable interface :
MyRunnable runnable=new
MyRunnable();
Thread thread=new Thread(runnable);
2. And then create Thread object by calling constructor and passing reference of Runnable interface i.e. runnable object :
Thread thread=new
Thread(runnable);
We should implement Runnable interface or extend Thread class. What are differences between implementing Runnable and
extending Thread?
Well the answer is you must extend Thread only when you are looking to modify run() and other methods as well. If you are simply
looking to modify only the run() method implementing Runnable is the best option (Runnable interface has only one abstract method
i.e. run() ).
1. Multiple inheritance in not allowed in java : When we implement Runnable interface we can extend another class as well, but if we
extend Thread class we cannot extend any other class because java does not allow multiple inheritance. So, same work is done by
implementing Runnable and extending Thread but in case of implementing Runnable we are still left with option of extending some other
class. So, it’s better to implement Runnable.
2. Thread safety : When we implement Runnable interface, same object is shared amongst multiple threads, but when we extend Thread
class each and every thread gets associated with new object.
3. Inheritance (Implementing Runnable is lightweight operation) : When we extend Thread unnecessary all Thread class features are
inherited, but when we implement Runnable interface no extra feature are inherited, as Runnable only consists only of one abstract
method i.e. run() method. So, implementing Runnable is lightweight operation.
4. Coding to interface : Even java recommends coding to interface. So, we must implement Runnable rather than extending thread. Also,
Thread class implements Runnable interface.
5. Don’t extend unless you wanna modify fundamental behaviour of class, Runnable interface has only one abstract method i.e.
run() : We must extend Thread only when you are looking to modify run() and other methods as well. If you are simply looking to
modify only the run() method implementing Runnable is the best option (Runnable interface has only one abstract method i.e. run() ).
We must not extend Thread class unless we're looking to modify fundamental behaviour of Thread class.
6. Flexibility in code when we implement Runnable : When we extend Thread first a fall all thread features are inherited and our class
becomes direct subclass of Thread , so whatever action we are doing is in Thread class. But, when we implement Runnable we create a
new thread and pass runnable object as parameter, we could pass runnable object to executorService & much more. So, we have
more options when we implement Runnable and our code becomes more flexible.
7. ExecutorService : If we implement Runnable, we can start multiple thread created on runnable object with ExecutorService
(because we can start Runnable object with new threads), but not in the case when we extend Thread (because thread can be started only
once).
How can you ensure all threads that started from main must end in order in which they started and also main should
end in last? (Important)
Join() method - ensure all threads that started from main must end in order in which they started and also main
should end in last. Types of join() method in java
Interviewers tend to know interviewees knowledge about Thread methods. So this is time to prove your point by
answering correctly. We can use join() method to ensure all threads that started from main must end in order in which they started and
also main should end in last. In other words waits for this thread to die.
Calling join() method internally calls join(0);
Definition : join() We can use join() method to ensure all threads that started from main must end in order in which they started
and also main should end in last. In other words waits for thread to die on which thread has been called.
Exception : join() method throws InterruptedException, in our case we have thrown exception.
instance method : join() is a instance method, hence we need to have thread instance for calling this method.
Thread state : when join() method is called on thread it goes from running to waiting state. And wait for thread to die.
synchronized block : thread need not to acquire object lock before calling join() method i.e. join() method can be called from
outside synchronized block.
3. join(long millis, int nanos) - Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.
To achieve we are going to create 2 threads on Runnable Object, create for loop in run() method and start both threads. After starting each
Thread call join() method on them to ensure they end in order in which they has started.
System.out.println("i="+i+" ,ThreadName="+Thread.currentThread().getName());
}
}
}
public class MyClass {
public static void main(String...args) throws InterruptedException{
System.out.println("In main() method");
MyRunnable runnable=new MyRunnable();
Thread thread1=new Thread(runnable);
Thread thread2=new Thread(runnable);
thread1.start();
thread1.join();
thread2.start();
thread2.join();
First, main thread was called, it started Thread1 and then we called join() method on Thread1, once Thread1 ended main thread started
Thread2 and we called join() method on Thread2, once Thread2 ended main thread also ended.
In short - calling thread1.join() made main thread to wait until Thread-1 dies.
Let’s discuss waiting time in detail : join() method have got few options.
4. join() : Waits for this thread to die.
5. join(long millis) - Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.
6. join(long millis, int nanos) - Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.
First, join(1000) will be called on Thread-1, but once 1000 millisec are up, main thread can resume and start thread2 (main thread
won’t wait for Thread-1 to die).
class MyRunnable implements Runnable{
public void run(){
System.out.println("in run() method");
for(int i=0;i<5;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("i="+i+" ,ThreadName="+Thread.currentThread().getName());
}
}
}
public class MyClass {
public static void main(String...args) throws InterruptedException{
System.out.println("In main() method");
MyRunnable runnable=new MyRunnable();
Thread thread1=new Thread(runnable);
Thread thread2=new Thread(runnable);
thread1.start();
thread1.join(1000); //once 1000 millisec are up, main thread can resume and start
thread2.
thread2.start();
thread2.join();
System.out.println("end main() method");
}
}
/*OUTPUT
In main() method
in run() method
i=0 ,ThreadName=Thread-0
i=1 ,ThreadName=Thread-0
in run() method
i=2 ,ThreadName=Thread-0
i=0 ,ThreadName=Thread-1
i=1 ,ThreadName=Thread-1
i=3 ,ThreadName=Thread-0
i=2 ,ThreadName=Thread-1
i=4 ,ThreadName=Thread-0
i=3 ,ThreadName=Thread-1
i=4 ,ThreadName=Thread-1
end main() method
*/
What is difference between starting thread with run() and start() method? (Important)
This is quite interesting question, it might confuse you a bit and at time may make you think is there really any difference between starting
thread with run() and start() method.
When you call start() method, main thread internally calls run() method to start newly created thread. So run() method is ultimately
called by newly created thread.
When you call run() method main thread rather than starting run() method with newly thread it start run() method by itself.
Let’s use start() method to start a thread>
class MyRunnable implements Runnable{
public void run(){ //overrides Runnable's run() method
System.out.println("in run() method");
System.out.println("currentThreadName= "+
Thread.currentThread().getName());
}
}
public class MyClass {
public static void main(String args[]){
System.out.println("currentThreadName= "+
Thread.currentThread().getName());
MyRunnable runnable=new MyRunnable();
Thread thread=new Thread(runnable);
thread.start();
}
}
/*OUTPUT
currentThreadName= main
in run() method
currentThreadName= Thread-0
*/
If we note output, when we called start() from main thread, run() method was called by new Thread (i.e. Thread-0).
1. Volatile can be used as a keyword against the variable, we cannot use volatile against method declaration.
volatile void method1(){} //it’s illegal, compilation error.
volatile int i; //legal
While synchronization can be used in method declaration or we can create synchronization blocks. Variables cannot be
synchronized.
Synchronized method:
synchronized void method2(){} //legal
Synchronized block:
void method2(){
synchronized (this) {
//code inside synchronized block.
}
}
2. Volatile does not acquire any lock on variable or object, but Synchronization acquires lock on method or block in which it is
used.
3. Volatile variables are not cached, but variables used inside synchronized method or block are cached.
4. When volatile is used will never create deadlock in program, as volatile never obtains any kind of lock . But in case if
synchronization is not done properly, we might end up creating dead lock in program.
5. Synchronization may cost us performance issues, as one thread might be waiting for another thread to release lock on object. But
volatile is never expensive in terms of performance.
6. A compile-time error will occur if a final variable is declared volatile.
volatile final int x = 0; //The field x can be either final or volatile, not
both.
7. Performance issue - As volatile keyword is not cached in CPU, it is always read from main memory, so in terms of performance
it’s always expensive to use volatile keyword.
package com.home.java.demo.thread;
package com.home.java.demo.thread;
@Override
public void run()
{
// System.out.println(Thread.currentThread().getName()+" old NV: "+volatileObject.getCounter());
// volatileObject.increaseCounter();
// System.out.println(Thread.currentThread().getName()+" New NV: "+volatileObject.getCounter());
System.out.println(Thread.currentThread().getName()+" old V: "+volatileObject.getVcounter());
volatileObject.increaseVCounter();;
System.out.println(Thread.currentThread().getName()+" New V: "+volatileObject.getVcounter());
}
}
package com.home.java.demo.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
}
}
Full program to show that how synchronization block can cost us performance,
we will create two threads on same object, then start both threads, either of the thread will acquire object lock and
other thread will wait to acquire lock until lock is released by thread which acquired it>
public class MyClass implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" is waiting for lock");
synchronized (this) {
try {
System.out.println(Thread.currentThread().getName()+" has acquired lock");
Thread.sleep(2000); //sleep for 2 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" has ended");
}
Here i have shown example code that how synchronized block can cost us performance, likewise you may call any
synchronized method from run() method, to see how synchronized method can cost us performance.
synchronization blocks and methods in java - Acquiring object lock - multiple threads may exist on same object but
only one thread of that object can enter synchronized block/method at a time.
In later posts we will learn how to acquire lock on class’s class object. Now, we will learn how to acquire object’s lock. It’s
very important to understand difference between object lock and class lock as well.
wait(), notify() and notifyAll() methods are always called from Synchronized block or synchronized methods only and
as soon as thread enters synchronized block it acquires object lock (by holding object monitor).
Let’s say there is one class MyClass and we have created it’s object and reference to that object is myClass. Now we can
create synchronization block, and parameter passed with synchronization tells which object has to be synchronized. In below
code, we have synchronized object reference by myClass.
MyClass myClass=new Myclass();
synchronized (myClass) {
//thread has acquired object lock on object referenced by myClass ( by acquiring myClass’s monitor.)
}
As soon thread entered Synchronization block, thread acquired object lock on object referenced by myClass (by acquiring
object’s monitor.)
Thread will leave lock when it exits synchronized block.
It’s important to know that multiple threads may exist on same object but only one thread of that object can enter
synchronized method at a time. Threads on different object can enter same method at same time.
synchronized (this) {
for(int i=0;i<5;i++){
System.out.println(i+" "+Thread.currentThread().getName()+" is executing");
try {
Thread.sleep(500);
} catch (InterruptedException e) {e.printStackTrace(); }
}
}
}
}
public class MyClass {
public static void main(String args[]) throws Exception {
MyRunnable obj = new MyRunnable();
Thread t1 = new Thread(obj,"Thread-1"); //Thread-1 on obj.
Thread t2 = new Thread(obj,"Thread-2"); //Thread-2 on obj.
t1.start();
t2.start();
}
}
/*OUTPUT
0 Thread-1 is executing
1 Thread-1 is executing
2 Thread-1 is executing
3 Thread-1 is executing
4 Thread-1 is executing
0 Thread-2 is executing
1 Thread-2 is executing
2 Thread-2 is executing
3 Thread-2 is executing
4 Thread-2 is executing
*/
If we note output, Thread-1 entered synchronization block and acquired obj’s lock meanwhile Thread-2 kept on waiting for
obj’s lock. And once Thread-1 completed Thread-2 acquired obj’s lock and started executing.
Example- Let’s say there is one class MyClass and we have created it’s object and reference to that object is myClass. Than
we started thread and from run method we called synchronized void method1().
As soon as thread entered Synchronization method, thread acquired object lock on object referenced by myClass (by
acquiring object’s monitor.)
Thread will leave lock when it exits synchronized method.
It’s important to know that multiple threads may exist on same object but only one thread of that object can enter
synchronized method at a time. Threads on different object can enter same method at same time.
/*OUTPUT
0 Thread-2 is executing
1 Thread-2 is executing
2 Thread-2 is executing
3 Thread-2 is executing
4 Thread-2 is executing
0 Thread-1 is executing
1 Thread-1 is executing
2 Thread-1 is executing
3 Thread-1 is executing
4 Thread-1 is executing
*/
If we note output, Thread-2 entered synchronized method and acquired obj’s lock meanwhile Thread-1 kept on waiting for
obj’s lock. And once Thread-2 completed Thread-1 acquired obj’s lock and started executing.
Program to show that IllegalThreadStateException is thrown when we try to start thread again>
public class MyClass implements Runnable{
@Override
public void run() {
System.out.println("in run() method, method completed.");
}
What is race condition in multithreading and how can we solve it? (Important)
This is very important question, this forms the core of multi threading, you should be able to explain about race condition in
detail. When more than one thread try to access same resource without synchronization causes race condition.
So we can solve race condition by using either synchronized block or synchronized method. When no two threads can
access same resource at a time phenomenon is also called as mutual exclusion.
Program to show that without synchronization problems will happen when 2 passengers try to book train ticket, dat too
when only 1 ticket was available >
class TicketBooking implements Runnable{
int ticketsAvailable=1;
//Let's say system takes some time in booking ticket (here we have taken 1 second time)
try{
Thread.sleep(1000);
}catch(Exception e){}
ticketsAvailable--;
System.out.println("Ticket BOOKED for : "+ Thread.currentThread().getName());
System.out.println("currently ticketsAvailable = "+ticketsAvailable);
}
else{
System.out.println("Ticket NOT BOOKED for : "+ Thread.currentThread().getName());
}
}
public class MyClass {
public static void main(String args[])
{
TicketBooking obj=new TicketBooking();
thread1.start();
thread2.start();
}
}
/*OUTPUT
Waiting to book ticket for : Passenger1 Thread
Waiting to book ticket for : Passenger2 Thread
Booking ticket for : Passenger1 Thread
Booking ticket for : Passenger2 Thread
Ticket BOOKED for : Passenger1 Thread
currently ticketsAvailable = 0
Ticket BOOKED for : Passenger2 Thread
currently ticketsAvailable = -1
*/
If we note the above program,
first Passenger1 Thread and Passenger2 Thread waited to book tickets.
Than, both threads tried to check the available ticket count and it was 1.
Both threads were able to book ticket.
And ultimately available ticket was reduced to -1, which is practically impossible, tickets count can never dip below 0.
RACE CONDITION PROBLEM : 1 ticket was booked by 2 passengers.
Program to show that with synchronization no problems will happen when 2 passengers try to book train ticket, dat too
when only 1 ticket was available>
class TicketBooking implements Runnable{
int ticketsAvailable=1;
//Let's say system takes some time in booking ticket (here we have taken 1 second time)
try{
Thread.sleep(1000);
}catch(Exception e){}
ticketsAvailable--;
System.out.println("Ticket BOOKED for : "+ Thread.currentThread().getName());
System.out.println("currently ticketsAvailable = "+ticketsAvailable);
}
else{
System.out.println("Ticket NOT BOOKED for : "+
Thread.currentThread().getName());
}
}
public class MyClass {
public static void main(String args[])
{
TicketBooking obj=new TicketBooking();
Thread thread1=new Thread(obj,"Passenger1 Thread");
Thread thread2=new Thread(obj,"Passenger2 Thread");
thread1.start();
thread2.start();
}
}
/*OUTPUT
Waiting to book ticket for : Passenger2 Thread
Waiting to book ticket for : Passenger1 Thread
Booking ticket for : Passenger2 Thread
Ticket BOOKED for : Passenger2 Thread
currently ticketsAvailable = 0
Ticket NOT BOOKED for : Passenger1 Thread
*/
If we note the above program,
first Passenger1 Thread and Passenger2 Thread waited to book tickets.
Than, Passenger1 Thread entered the synchronized block and acquired object lock, but Passenger2 Thread wasn’t able to
acquire object lock and was waiting for Passenger1 Thread to release object lock.
By the time Passenger1 Thread was successfully able to book ticket and reduce the available ticket count to 0, and then
release object lock by exiting synchronized block.
Than Passenger2 Thread got a chance to acquire object lock, but available ticket count at that time was 0 so it wasn’t able
to book ticket.
RACE CONDITION PROBLEM SOLVED : 1 ticket was booked by only 1 passenger, while other wasn’t able to
book any ticket.
Definitions :
notify() - Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of
them is chosen to be awakened. The choice is random and occurs at the discretion of the implementation. A thread waits on
an object's monitor by calling one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
notifyAll() - Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor
by calling one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
wait() - Causes the current thread to wait until another thread invokes the notify() or notifyAll() method for this
object.
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another
thread notifies threads waiting on this object's monitor to wake up either through a call to the notify()/ notifyAll() method.
The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
Thread state :
>By calling wait() method thread go from running to waiting state. In waiting state it will wait for other threads
to release object monitor/lock.
> Once notify() or notifyAll() method is called object monitor/lock becomes available and thread can again return to
runnable state.
synchronized block : thread needs to to acquire object lock before calling wait() and notify() methods i.e. these
methods can be called only from synchronized block or synchronized method.
Exception : As mentioned above before calling these methods thread must own object’s monitor means wait() and
notify() methods must be called from synchronized blocks or synchronized method otherwise IllegalMonitorStateException
is thrown at runtime.
Waiting time : wait() and notify() method have got few options.
1. wait() - It internally calls wait(0).
2. wait(long timeout) - Causes the current thread to wait until either another thread invokes the notify() or
notifyAll() methods for this object, or a specified timeout time has elapsed.
3. wait(long timeout, int nanos) - Causes the current thread to wait until either another thread invokes the
notify() or notifyAll() methods for this object, or a specified timeout time plus the specified number of
nanoseconds has elapsed.
Instance methods : wait() and notify() are instance methods and are always called on objects.
Native methods : implementation of wait() and notify() methods are provided by JVM.
Let’s see definition of wait() and notify() method as given in java.lang.Object -
public final void wait() throws InterruptedException
Belongs to which class : wait() and notify() methods belongs to java.lang.Object class.
Below i tried to give a very simple example to show usgae of wait() and notify() method to give you better understanding of
these methods.
Solve Consumer Producer problem by using wait() and notify() methods, where consumer can consume only when
production is over.
Producer will allow consumer to consume only when 10 products have been produced (i.e. when production is over).
Thought, we can solve this producer consumer problem without using wait() and notify() method as well, below i have
given consequences of not using using wait() and notify().
In program consumer thread will start() and wait by calling wait() method till producer is producing. Once
production is over, producer thread will call notify() method, which will notify consumer thread and consumer will
start consuming.
import java.util.ArrayList;
/* Producer is producing, Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
ArrayList<Integer> sharedQueue;
Producer(){
sharedQueue=new ArrayList<Integer>();
}
@Override
public void run(){
synchronized (this) {
for(int i=1;i<=10;i++){ //Producer will produce 10 products
sharedQueue.add(i);
System.out.println("Producer is still Producing, Produced : "+i);
try{
Thread.sleep(1000);
}catch(InterruptedException e){e.printStackTrace();}
}
System.out.println("Production is over, consumer can consume.");
this.notify(); //Production is over, notify consumer thread so that consumer can consume.
}
}
}
class Consumer extends Thread{
Producer prod;
Consumer(Producer obj){
prod=obj;
}
}
public class ProducerConsumerWithWaitNotify {
public static void main(String args[]) throws InterruptedException{
But what could be consequences of not using using wait() and notify() to solve above producer consumer problem?
It will cost of us performance. Consumer thread will unnecessarily repeatedly check whether producer has completed
it’s production or not, but when wait() and notify() were used, consumer thread started, called wait() and waited for
producer thread to notify.
Let’s identify Problem statement in not using wait() and notify()>
while(this.prod.productionInProcess)
Using while loop is the actual problem statement in not using wait() and notify(), loops generally costs us performance and
we must try to avoid loops.
Let’ say producer was to producer 100 products and for every production it takes 10 seconds & consumer is checking after
every 20seconds whether production is over or not. In that case consumer will check after every every 2 products produced
whether production is over or not, unnecessary 50 calls will be made, which will of course slow down our whole process.
But now, let's solve above problem without using wait() and notify() - approach which won’t be performance friendly (but
provides developers a choice to solve producer consumer problem in different manner).
In program producer thread will start() and it will start producing and called sleep(1000) in between, which will give
consumer thread chance to execute. consumer checks whether productionInProcess is true or not, if it's true,
consumer will sleep(4000) and wake up after specified time and again check whether productionInProcess is true or
false. process will repeat till productionInProcess is true. Meanwhile, producer thread will complete production and
ultimately make productionInProcess to false. Once productionInProcess is false, consumer will consume.
import java.util.ArrayList;
/* Producer is producing, Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
boolean productionInProcess;
ArrayList<Integer> list;
Producer(){
productionInProcess=true; //initially Producer will be producing, so make this productionInProcess true.
list=new ArrayList<Integer>();
}
@Override
public void run(){
try{
Thread.sleep(1000);
}catch(InterruptedException e){e.printStackTrace();}
}
productionInProcess=false; // Once production is over, make this productionInProcess false.
//Production is over, consumer can consume.
}
class Consumer extends Thread{
Producer prod;
Consumer(Producer obj){
prod=obj;
}
}
public class ProducerConsumerWithoutWaitNotify {
public static void main(String args[]){
}
}
/*OUTPUT
Consumer waiting for production to get over.
Producer is still Producing, Produced : 1
Producer is still Producing, Produced : 2
Producer is still Producing, Produced : 3
Producer is still Producing, Produced : 4
Producer is still Producing, Produced : 5
Producer is still Producing, Produced : 6
Producer is still Producing, Produced : 7
Producer is still Producing, Produced : 8
Producer is still Producing, Produced : 9
Producer is still Producing, Produced : 10
Production is over, consumer can consume.
Consumed : 1
Consumed : 2
Consumed : 3
Consumed : 4
Consumed : 5
Consumed : 6
Consumed : 7
Consumed : 8
Consumed : 9
Consumed : 10
*/
Why wait(), notify() and notifyAll() are in Object class and not in Thread class in java
1. Every Object has a monitor, acquiring that monitors allow thread to hold lock on object. But Thread class does not
have any monitors.
2. wait(), notify() and notifyAll() are called on objects only > When wait() method is called on object by thread it
waits for another thread on that object to release object monitor by calling notify() or notifyAll() method on
that object.
When notify() method is called on object by thread it notifies all the threads which are waiting for that object monitor
that object monitor is available now.
So, this shows that wait(), notify() and notifyAll() are called on objects only.
3. Wait(), notify() and notifyAll() method being in Object class allows all the threads created on that object to
communicate with other. [As multiple threads may exist on same object].
4. As multiple threads exists on same object. Only one thread can hold object monitor at a time. As a result thread
can notify other threads of same object that lock is available now. But, thread having these methods does not make
any sense because multiple threads exists on object it's not other way around (i.e. multiple objects exists on
thread).
5. Now let’s discuss one hypothetical scenario, what will happen if Thread class contains wait(), notify() and
notifyAll() methods?
Having wait(), notify() and notifyAll() methods means Thread class also must have their monitor.
Every thread having their monitor will create few problems -
>Thread communication problem.
>Synchronization on object won’t be possible- Because object has monitor, one object can have multiple threads
and thread hold lock on object by holding object monitor. But if each thread will have monitor, we won’t have any way of
achieving synchronization.
>Inconsistency in state of object (because synchronization won't be possible).
Is it important to acquire object lock before calling wait(), notify() and notifyAll()?
Yes, it’s mandatory to acquire object lock before calling these methods on object. As discussed above wait(), notify() and
notifyAll() methods are always called from Synchronized block only, and as soon as thread enters synchronized block
it acquires object lock (by holding object monitor). If we call these methods without acquiring object lock i.e. from outside
synchronize block then java.lang. IllegalMonitorStateException is thrown at runtime.
Wait() method needs to enclosed in try-catch block, because it throws compile time exception i.e. InterruptedException.
How can you solve consumer producer problem by using wait() and notify() method? (Important)
Here come the time to answer very very important question from interview perspective. Interviewers tends to check how
sound you are in threads inter communication. Because for solving this problem we got to use synchronization blocks,
wait() and notify() method very cautiously. If you misplace synchronization block or any of the method, that may
cause your program to go horribly wrong. So, before going into this question first i’ll recommend you to understand how
to use synchronized blocks, wait() and notify() methods.
Solve Consumer Producer pattern by using wait() and notify() methods in multithreading in java
Here come the time to answer very very important question from interview perspective. Interviewers tends to check how
sound you are in threads inter communication. Because for solving this problem we got to use synchronization blocks,
wait() and notify() method very cautiously. If you misplace synchronization block or any of the method, that may
cause your program to go horribly wrong. So, before going into this question first i’ll recommend you to understand how
to use synchronized blocks, wait() and notify() methods.
consumerThread.start();
consumerThread will enter run method and call consume() method. There it will check for sharedQueue’s size.
-if size is equal to 0 that means producer hasn’t produced any product, wait for producer to produce by using
below piece of code-
synchronized (sharedQueue) {
while (sharedQueue.size() == 0) {
sharedQueue.wait();
}
}
-if size is greater than 0, consumer will start consuming by using below piece of code.
synchronized (sharedQueue) {
Thread.sleep((long)(Math.random() * 2000));
System.out.println("consumed : "+ sharedQueue.remove(0));
sharedQueue.notify();
}
producerThread.start();
producerThread will enter run method and call produce() method. There it will check for sharedQueue’s size.
-if size is equal to 2 (i.e. maximum number of products which sharedQueue can hold at a time), wait for consumer
to consume by using below piece of code-
synchronized (sharedQueue) {
while (sharedQueue.size() == maxSize) { //maxsize is 2
sharedQueue.wait();
}
}
-if size is less than 2, producer will start producing by using below piece of code.
synchronized (sharedQueue) {
System.out.println("Produced : " + i);
sharedQueue.add(i);
Thread.sleep((long)(Math.random() * 1000));
sharedQueue.notify();
}
Full Program/sourceCode to solve consumer producer problem using wait() and notify() method>
import java.util.LinkedList;
import java.util.List;
/**
* Producer Class.
*/
class Producer implements Runnable {
private List<Integer> sharedQueue;
private int maxSize=2; //maximum number of products which sharedQueue can hold at a time.
public Producer(List<Integer> sharedQueue) {
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
for (int i = 1; i <= 10; i++) { //produce 10 products.
try {
produce(i);
} catch (InterruptedException e) { e.printStackTrace(); }
}
}
private void produce(int i) throws InterruptedException {
synchronized (sharedQueue) {
//if sharedQuey is full wait until consumer consumes.
while (sharedQueue.size() == maxSize) {
System.out.println("Queue is full, producerThread is waiting for "
+ "consumerThread to consume, sharedQueue's size= "+maxSize);
sharedQueue.wait();
}
}
@Override
public void run() {
while (true) {
try {
consume();
Thread.sleep(100);
} catch (InterruptedException e) { e.printStackTrace(); }
}
}
private void consume() throws InterruptedException {
synchronized (sharedQueue) {
//if sharedQuey is empty wait until producer produces.
while (sharedQueue.size() == 0) {
System.out.println("Queue is empty, consumerThread is waiting for "
+ "producerThread to produce, sharedQueue's size= 0");
sharedQueue.wait();
}
}
}
public class ProducerConsumerWaitNotify {
public static void main(String args[]) {
List<Integer> sharedQueue = new LinkedList<Integer>(); //Creating shared object
How can you solve consumer producer pattern by using BlockingQueue? (Important)
Now it’s time to gear up to face question which is most probably going to be followed up by previous question i.e. after how
to solve consumer producer problem using wait() and notify() method. Generally you might wonder why interviewer's are so
much interested in asking about solving consumer producer problem using BlockingQueue, answer is they want to know
how strong knowledge you have about java concurrent Api’s, this Api use consumer producer pattern in very optimized
manner, BlockingQueue is designed is such a manner that it offer us the best performance.
BlockingQueue is a interface and we will use its implementation class LinkedBlockingQueue.
Solve Consumer Producer problem by using BlockingQueue in multithreading in java - Detailed explanation with
full program
In this thread concurrency tutorial we will learn how to Solve Consumer Producer problem by using BlockingQueue and
LinkedBlockingQueue in multithreading in java using example and program.
Now it’s time to gear up to face question which is most probably going to be followed up by previous question i.e. how to
solve consumer producer problem using wait() and notify() method in java. Generally you might wonder why interviewer's
are so much interested in asking this question, answer is they want to know how strong knowledge you have about java
concurrent Api’s, this Api use consumer producer pattern in very optimized manner, BlockingQueue is designed is such a
manner that it offer us the best performance in java.
BlockingQueue is a interface and we will use its implementation class LinkedBlockingQueue. In one my post i have
mentioned how to implement custom BlockingQueue and solving Producer Consumer pattern using Custom implementation
of BlockingQueue interface.
Key methods in BlockingQueue Api for solving consumer producer in java pattern are >
Example/ Full Program/sourceCode to solve consumer producer problem using custom BlockingQueue in java >
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Producer Class in java.
*/
class Producer implements Runnable {
private final BlockingQueue<Integer> sharedQueue;
public Producer(BlockingQueue<Integer> sharedQueue) {
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
for(int i=1; i<=10; i++){
try {
System.out.println("Produced : " + i);
//put/produce into sharedQueue.
sharedQueue.put(i);
} catch (InterruptedException ex) {
}
}
}
}
/**
* Consumer Class in java.
*/
class Consumer implements Runnable{
private BlockingQueue<Integer> sharedQueue;
public Consumer (BlockingQueue<Integer> sharedQueue) {
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
while(true){
try {
//take/consume from sharedQueue.
System.out.println("CONSUMED : "+ sharedQueue.take());
} catch (InterruptedException ex) {
}
}
}
}
public class ProducerConsumerBlockingQueue {
public static void main(String args[]){
SUMMARY >
So, in this thread concurrency tutorial we learned how to Solve Consumer Producer problem by using BlockingQueue
and LinkedBlockingQueue in multithreading in java.
Difference between String, StringBuffer and StringBuilder is a very important interview question. It’s very
basic question which every developer must know.
Here I have covered few in depth differences as well which will be handy for experienced developers.
Example -->
String s1 = "abc"; StringBuffer is StringBuilder is
> in string pool area of heap. created in heap. created in heap.
Please see
example 2 Please see
below. example 3 below.
4 Performance Value of String in String pool is cached, hence Because of Because of non
making it fast. synchronized synchronized
methods its slow. methods its fast.
String created with new operator is also fast
process.
So,
String str = new
StringBuilder(str).append("def").toString();
Example 1a -->
System.out.println(str);
str is referring to “ab” and string “abcd” will be eligible for garbage collection.
Example 1b -->
What will happen when below 2 statements will execute >
str = "abcd";
Now, No string with “abcd” is there in string pool, so JVM will create new string “abcd” in string pool and str will be a
reference variable which will refer to it.
String "abcd" will stay in string pool but reference to it will be lost, and it will be eligible for garbage collection.
Example 2-->
sBuffer= sBuffer.append("cd");
> “cd” will be added to StringBuffer object referred by sBuffer. So, “abcd” will be formed.
(Note: addition was made to previous object, no new object was formed,
Behaviour was different as compared to immutable String’s concat function
)
Example 3-->
>JVM will create stringBuilder object “ab” in heap and sBuilder will be a reference variable which will refer to it.
sBuilder=sBuilder. append("cd");
> “cd” will be added to StringBuilder object referred by sBuilder. So, “abcd” will be formed.
(Note: addition was made to previous object, no new object was formed,
Behaviour was different as compared to immutable String’s concat function
)
System.out.println(sBuilder);
What is reflection in java? Have you ever used reflection directly or directly?
Reflection in java>
Reflection is used to load java classes at runtime. Frameworks like struts, spring and hibernate uses reflection for loading classes at
runtime.
Let’s understand step-by-step how Reflection program will work in java >
Step 1 > load 'ReflectionClass' at runtime, please ensure you write package name before class name.
Step 2 > create object of ReflectionClass by calling constructor of ReflectionClass
Step 3 > calling methodNoPara() method of ReflectionClass.
Method throws
Class.forName("reflection1.ReflectionClass" ClassNotFoundException
)
cls.newInstance() InstantiationException
IllegalAccessException
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*OUTPUT
in constructor of ReflectionClass
in methodNoPara() of ReflectionClass
in methodString() > ankit
in methodInteger() > 911
*/
Static keyword in java - variable, method, class, block - 25 salient features - Differences between static and instance/non-static
variable, methods, block and nested class
1) Static variable
static variables are also known as class variables.
We need not to create instance of class for accessing static variables
static variables will remain same for different instance/objects of class but for every new object instance variables will be
initialized to new value.
Static variables can be used inside constructor.
Static variables are not serialized in java.
Diagram to where static variables are stored in memory & static variables remain same for different objects of class>
It's important to know that only the static variables and their values (primitives or references) are stored in PermGen space.
If static variable is a reference to an object that which is stored in the normal sections of the heap (string pool, young/old generation or
survivor space). Those objects are not stored in PermGen space.
Example code >
static int id = 1; //the value 1 is stored in the permgen area.
static Employee emp = new Employee (); //the reference(i.e. emp ) is
//stored in the permgen area, the object is not
static String company="XYZ pvt ltd"; //the reference(i.e. company)
is
//stored in the permgen area, but "XYZ pvt ltd" is not,
//"XYZ pvt ltd" gets stored in String pool.
Program to show value of static variables will remain same for different objects of class but for every new object instance variables will be
initialized to new value>
class Employee{
int id;
String name;
static String company="XYZ pvt ltd";
Static variables can be accessed inside > Non-static variables can be accessed inside >
static block, non-static block (instance block), non-static block (instance block),
static method, non-static method (instance method), non-static method (instance method),
methods of static nested class and inner class. methods of inner class.
in methods of static nested class.
Static variables are class variables access to them is always Non-Static variables are instance variables access to them is always
resolved during compile time. resolved during runtime.
Static variables are not serialized in java instance variables are serialized in java
2) Static method
static methods are also known as class methods.
We need not to create instance of class for accessing static methods.
Static methods can access all static variables, but cannot access non-static (instance variables)
Important points about overriding static methods >
Static method cannot be overridden, any attempt to do this will not cause compilation error.
Static method cannot be overridden with non-static method, any attempt to do this will cause compilation error.
Non-static method cannot be overridden with static method, any attempt to do this will cause compilation error.
Program for accessing static method>
public class StaticMethodTest{
public static void main(String[] args) {
staticMethod();
}
static void staticMethod() {
System.out.println("in staticMethod()");
}
}
/*OUTPUT
in staticMethod()
*/
Only static variables can be accessed inside static method Static and non-static variables (instance variables) can be accessed
inside static method.
We need not to create instance of class for accessing static methods. We need to create instance of class for accessing non-static
methods.
Because static methods are class methods, access to them is always Because non static methods are instance methods, access to them is
resolved during compile time only using the compile time type always resolved during runtime time only using the runtime object.
information.
EXAMPLE>
In below program access to SuperClass’s static method() is resolved during compile time only using the compile time type information (i.e.
by using SuperClass obj), means calling obj.method() is always going to invoke static method() of SuperClass.
Assign any sub type object to reference of superclass [obj=new SubClass()] won’t have any impact on call to static method at runtime.
Accessing static method using object references is bad practice (discussed above) and just an extra liberty given by the java designers.
Program to static method cannot be overridden>
class SuperClass{
static void method(){
System.out.println("superClass method");
}
}
class SubClass extends SuperClass{
static void method(){
System.out.println("SubClass method");
}
}
public class StaticMethodTest {
}
/*OUTPUT
superClass method
*/
If non-static methods would have been used in above program, output would have been
subClass method
3) Static class
static class are also known as
static nested classes
Top level class can never be static in java.
Only static variables can be accessed inside static nested class.
StaticNestedClass can be abstract or final.
StaticNestedClass can be private, protected, public.
strictfp modifier can also be used with StaticNestedClass.
Static nested classes can declare static initialization blocks
Static nested classes can declare member interfaces.
Note : Static nested class is not a inner class, its just a nested class.
Program for accessing static nested class>
class Employee{
//Inner class
class InnerClass {
public void method() {
System.out.println("In InnerClass's method");
}
}
}
/*OUTPUT
In InnerClass's method
In StaticNestedClass's method
*/
Top level class can never be static in java. Top level class is always non static in java.
static class are also known as static nested classes. Top level class is just called as class .
But,
nested class is known as >
inner class or
member inner class.
Only Static member variables of outer class can be accessed inside Static and non-static member variables of outer class can be
methods of static nested class. accessed inside methods of non-static class
-Instance of top level class is not needed, we need to have instance Instance of top level class and InnerClass is needed.
of static nested class only
static blocks executes before instance blocks. instance blocks executes after static blocks.
Only static variables can be accessed inside static Static and non-static variables (instance variables) can be accessed inside instance
block block.
static blocks can be used for initializing static instance blocks can be used for initializing instance variables
variables or
or calling any instance method.
calling any static method.
static blocks executes when class is loaded. instance block executes only when instance of class is created, not called when class
is loaded.
this keyword cannot be used in static blocks. this keyword can be used in instance block.
Program to show static blocks are called as soon as class is loaded even before instance of class is created (i.e. before constructor is
called) >
class Employee {
/*
* Static block
*/
static {
System.out.println("static block");
}
/*
* Non-Static block (Instance block)
*/
{
System.out.println("non-static block");
}
/*
* Constructor
*/
Employee() {
System.out.println("Employee constructor");
}
}
public class StaticBlockTest {
public static void main(String[] args) {
}
/*OUTPUT
static block
non-static block
Employee constructor
*/
Static block
19. static blocks are also known as static initialization blocks in java.
20. static blocks executes as soon as class is loaded even before instance of class is created (i.e. before constructor is called).
21. static blocks executes before instance blocks.
22. Any code written inside static block is thread safe.
23. Only static variables can be accessed inside static block
24. static blocks can be used for initializing static variables or calling any static method.
25. this keyword cannot be used in static blocks.
Q65. Can we override static method in java?
Its one of the favourite question of interviewers. Intention is to test very basic core java concept.
Static method cannot be overridden, any attempt to do this will not cause compilation error, but the results won’t be same
when we would have overridden non-static methods.
But why?
Overriding in Java means that the method would be called on the run time based on type of the object and not on the compile
time type of it .
But static methods are class methods access to them is always resolved during compile time only using the compile time type
information.
It's one of the favourite question of interviewers. Intention is to test few basic core java concepts.
Static method cannot be overridden in java, any attempt to do this will not cause compilation error, but the results won’t be same when
we would have overridden non-static methods.
But why?
Overriding in Java means that the method would be called on the run time based on type of the object and not on the compile time type of it
But static methods are class methods access to them is always resolved during compile time only using the compile time type information.
Accessing static method using object references is a bad practice (we must access static variable using Class Name) and just an extra liberty
given by the java designers.
EXAMPLE>
In below program access to SuperClass’s static method() is resolved during compile time only using the compile time type information (i.e.
by using SuperClass obj), means calling obj.method() is always going to invoke static method() of SuperClass.
Assign any sub type object to reference of superclass [obj=new SubClass()] won’t have any impact on call to static method at runtime.
Accessing static method using object references is bad practice (discussed above) and just an extra liberty given by the java designers.
}
/*OUTPUT
superClass method
*/
If non-static methods would have been used in above program, output would have been
subClass method
Important points you must know about overriding static methods in java >
Static method cannot be overridden, any attempt to do this will not cause compilation error. (Discussed above)
Static method cannot be overridden with non-static method, any attempt to do this will cause compilation error.
Non-static method cannot be overridden with static method, any attempt to do this will cause compilation error.
How do you ensure different thread access different resources concurrently without deadlock?
Acquire lock on resources in a particular order and then releasing acquired lock in reverse order won’t create any deadlock.
Which method is called for garbage collection in java? What algorithm does garbage collector follows?
JVM calls finalize method on object for garbage collection
}
}
/*OUTPUT
in main() method
in finalize() method of Subclass, doing cleanup activity of Subclass
in finalize() method of SuperClass, doing cleanup activity SuperClass
*/
Subclass extends SuperClass. So, calling super.finalize() is valid because finalize method for object can be called from some other class
outside the package with inheritance.
finalize method for object can’t be called from some other class outside the package without inheritance
MyClass1 is in package com.ankit1
package com.ankit1;
public class MyClass1 {
@Override
protected void finalize() throws Throwable {
//....
}
}
MyClass2 is in package com.ankit2
MyClass1 does not extends MyClass2. So, calling finalize() method by creating instance of MyClass1 in MyClass2 is invalid (any attempt
to do so will cause compilation error) because finalize method for object can’t be called from some other class outside the package
without inheritance.
Singleton in java, Doubly Locked Singleton class/ Lazy initialization, enum singleton, eager initialization in static block
Use synchronized block inside method-so that 2 threads don’t create more than 1 instance of class concurrently.
This is also known as lazy initialization.
/**
* Singleton class - with Double checked Locking
*/
class Singleton {
//private > So that INSTANCE variable cannot be accessed outside class.
//static > So that INSTANCE variable can be accessed in static methods of class.
private static Singleton INSTANCE;
/**
* private constructor - so that class can't be instantiated outside this
* class
*/
private Singleton() {
}
/**
* Method which will return instance (only instance) of Singleton class.
*
* Method will perform double check and ensure no two threads form more than one
instance.
*
* Method is public so that it could be accessed outside class.
*
* Method is static so that it could be accessed without creating instance of class.
*
* Use synchronized block inside method-so that 2 threads don’t create more
* than 1 instance of class concurrently.
*/
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (INSTANCE == null)
INSTANCE = new Singleton();
return INSTANCE;
}
}
/**
* instance method of Singleton class.
*/
public void m() {
System.out.println("m()");
}
}
/**
* Main class
*/
public class SingletonClassTest {
public static void main(String... a) {
}
}
/*OUTPUT
m()
m()
true
*/
In the later part of program we conducted test to ensure instance return by Singleton class are same.
First we obtained 2 references i.e. obj1 and obj2 to instance of Singleton class returned by getInstance() method.
Then equality test was done using == operator.
obj1==obj2 returned True, means two references are referring to same instance of class.
Steps >
declare enum.
create private constructor.
Program to create Enum Singleton class>
/*
* Singleton enum - Are best way to create Singleton
* They are also thread safe.
*/
enum SingletonEnum {
SINGLETON_INSTANCE;
/** private constructor of enum. */
private SingletonEnum(){}
}
public class SingletonClassEnumTest {
public static void main(String...a){
System.out.println(SingletonEnum.SINGLETON_INSTANCE);
}
}
/*OUTPUT
SINGLETON_INSTANCE
true
*/
class Singleton {
private static final Singleton INSTANCE=new Singleton();
/**
* private constructor - so that class can't be instantiated outside this
* class
*/
private Singleton(){
}
public static Singleton getInstance() {
return INSTANCE;
}
}
class Singleton {
private static Singleton INSTANCE;
static{
INSTANCE=new Singleton();
}
/**
* private constructor - so that class can't be instantiated outside this
* class
*/
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
java is CALL BY VALUE (Pass by value) - NOT call by reference - With examples in java
In this core java tutorial we will learn in lots of detail that java is purely Pass by value and not Pass by reference with example, programs
and diagrams.
In java, arguments are passed by value (call by value/ Pass by value) only.
Java does not passes value by reference (call by reference/ Pass by reference).
First I will like to discuss what is difference between call by value and call by reference. And what happens in call by value and reference in
Question : What is Call by value (Pass by value)? And how java is call by value?
Answer : Call by value means Copy of an argument is passed to method. Therefore, any changes made to the argument in passed method
In java when any changes are made to the argument in passed method the value of original argument is not changed. Hence, Java is
call by value.
Question : What is Call by reference (Pass by reference)? And what happens in Call by reference? And how java is NOT call by
reference?
Answer : In Call by reference, reference of argument is passed to method. Therefore, any changes made to the argument in passed
In java when any changes are made to the argument in passed method the value of original argument is not changed. Hence, Java is
m(i, str); //PASS int primitive type and String object by VALUE
System.out.println("\nIn main(), AFTER passing by value i.e. AFTER calling method m()");
System.out.println("i = "+i+", str = "+str);
}
static void m(int i, String str){
i = 2;
str = "b";
System.out.println("\nIn method m(), after making changes to parameters");
System.out.println("i = "+i+", str = "+str);
}
}
/*OUTPUT
In main(), BEFORE passing by value i.e. BEFORE calling method m()
i = 1, str = a
In method m(), after making changes to parameters
i = 2, str = b
In main(), AFTER passing by value i.e. AFTER calling method m()
i = 1, str = a
*/
Now, let’s analyze about call by value example - In above example Copy of an argument is passed to method m() and therefore any
changes made to the argument in passed method i.e. m() didn’t change the value of original argument. in java
Program 2 - to demonstrate Call by value (Pass by value) - reference to object is passed by copy in java
Before reading below text I will like you to be careful about the terms in which reference is used. Do not mess up between reference to
Reference to object is passed by value (i.e. copy of reference is created and passed), reference to object is not at all passed by reference
in java.
Here in the below program, a is reference to object Emp a is passed by value (i.e. copy of a is created and passed), a is not at all passed
by reference, it may look like that a is passed by reference but actually that doesn't happens at all copy of a is created and that is passed to
class Emp{
int id;
public Emp(int id) {
this.id = id;
}
}
public class PassByValueExample2 {
public static void main(String[] args) {
Emp a=new Emp(1);
}
static void m(Emp b){
b.id = 2;
System.out.println("\nIn method m(), after making some changes");
System.out.println("b.id = " + b.id);
}
}
/*OUTPUT
In main(), BEFORE passing a by value i.e. BEFORE calling method m()
a.id = 1
In method m(), after making some changes
b.id = 2
In main(), AFTER passing a by value i.e. AFTER calling method m()
a.id = 2
*/
So, we can say that reference to object is passed by copy in java.
2.1) Let’s understand by diagram how in above program (program 2) reference to object is passed by copy in java >
m(a);
When method m is called, a is also passed to method m, but a is not directly passed to method m(), first copy of a is created and then passed
to method m.
b.id = 2;
b.id is assigned a new value, a and b are referring to same object so any changes made to b will be reflected in a as well.
We cannot change the reference in the called method i.e. the method in which reference to the object has been passed by copy, If in
case reference is changed in called method, the copy of reference in the called method will start pointing to the new object but
original reference will keep on pointing to old object only in java. We will understand this in next program.
Program 3 - In continuation to program 2 - to demonstrate Call by value (Pass by value) - reference to object is passed by copy in java
Reference to object is passed by value (i.e. copy of reference is created and passed), reference to object is not at all passed by reference.
Here in the below program, a is reference to object Emp, a is passed by value (i.e. copy of a is created and passed), a is not at all passed
by reference, it may look like that a is passed by reference but actually that doesn't happens at all copy of a is created and that is passed to
We cannot change the reference b in the method m(), if in case, b is changed, b will start pointing to the new object but original
class Emp{
int id;
public Emp(int id) {
this.id = id;
}
}
public class PassByValueExample3 {
public static void main(String[] args) {
Emp a=new Emp(1);
}
static void m(Emp b){
b = new Emp(2); //Now b will start pointing to newly created object
System.out.println("\nIn method m(), after making some changes");
System.out.println("b.id = " + b.id);
}
}
/*OUTPUT
In main(), BEFORE passing a by value i.e. BEFORE calling method m()
a.id = 1
In method m(), after making some changes
b.id = 2
In main(), AFTER passing a by value i.e. AFTER calling method m()
a.id = 1
*/
3.1) Let’s understand by diagram how in above program (program 3) reference to object is passed by copy in java >
m(a);
When method m is called, a is also passed to method m, but a is not directly passed to method m(), first copy of a is created and then passed
to method m.
b = new Emp(2);
b is assigned new Emp object. So, b will start pointing to the new object but original reference i.e. a will keep on pointing to old object only.
So in this core java tutorial we learned in lots of detail that java is purely Pass by value and not Pass by reference with example, programs
and diagrams.
Types of Inner classes with example - Inner class, static nested class, local and anonymous inner class in java, Difference between
static and non-static class
1) Inner class
1.1) An inner class is a nested class that is not explicitly or implicitly declared static.
1.2) Inner class is also known as
member inner class.
1.3) Inner class is considered as instance member variable of outer class.
1.4) Inner class has access to all other member variables of outer class. Inner class can access -
instance member variable of outer class
instance methods of outer class
static member variable of outer class
static methods of outer class
Outer class reference
Inner class reference
Inner class is instance specific/ object specific class. It has got access to this reference of outer class.
o Hence, can access OuterClass instance variable and instance method using OuterClass reference this.
class OuterClass{
//Inner class
class InnerClass {
//Inner classes cannot not declare static initialization
blocks
static{} //compilation error
class A{
//Inner classes can inherit static members that are not constant
variables
static int x = 1;
}
class OuterClass {
// Inner class
class InnerClass extends A{
System.out.println("OuterClass reference="+OuterClass.this);
System.out.println("InnerClass reference="+this);
}
} //End InnerClass
}
/**
* Main class
*/
public class InnerClassTest {
public static void main(String[] args) {
}
/*OUTPUT
In InnerClass's method
OuterClass reference=com.ankit.OuterClass@1a4eb98b
InnerClass reference=com.ankit.OuterClass$InnerClass@2677622b
*/
When above program is compiled following .class files are formed >
OuterClass.class > OuterClass
OuterClass$InnerClass.class >InnerClass
InnerClassTest.class >InnerClassTest (Main class)
2.1) Method of nested class can only be static if nested class is a static nested class.
2.2) Static nested class is considered as static member variable of outer class.
2.3) StaticNestedClass has access to all static member variables and static methods of OuterClass.
2.4) StaticNestedClass can be abstract or final.
2.5) StaticNestedClass can be private, protected, public.
2.6) strictfp modifier can also be used with StaticNestedClass.
class OuterClass {
// StaticNestedClass
static class StaticNestedClass {
// StaticNestedClass can declare static initialization blocks
static {
}
// StaticNestedClass can declare member interfaces.
interface I {
}
// StaticNestedClass can declare static members
static int i = 2;
// StaticNestedClass can declare constant variables
static final int j = 3;
//StaticNestedClass constructor
StaticNestedClass() {}
}
}
}//End StaticNestedClass
}
/**
* Main class
*/
public class NestedClassTest {
public static void main(String[] args) {
}
/*OUTPUT
In StaticNestedClass's method
*/
static class are also known as static nested classes. Top level class is just called as class .
But,
nested class is known as >
inner class or
member inner class.
Only Static member variables of outer class can be accessed inside Static and non-static member variables of outer class can be
methods of static nested class. accessed inside methods of non-static class
-Instance of top level class is not needed, we need to have instance Instance of top level class and InnerClass is needed.
of static nested class only
When above program is compiled following .class files are formed >
OuterClass.class > OuterClass
OuterClass$StaticNestedClass.class >StaticNestedClass
InnerClassTest.class >InnerClassTest (Main class)
Note : Static nested class is not a inner class, its just a nested class.
class OuterClass{
//LocalInnerClass inside instance block
{
class A{}
}
void myMethod(){
//LocalInnerClass inside if statement
if(true){
class A{}
}
System.out.println("OuterClass reference="+OuterClass.this);
System.out.println("InnerClass reference="+this);
}
} //End LocalInnerClass
}
/**
* Main class
*/
public class InnerClassTest {
public static void main(String[] args) {
}
/*OUTPUT
In LocalInnerClass's method
OuterClass reference=com.ankit.OuterClass@2677622b
InnerClass reference=com.ankit.OuterClass$1LocalInnerClass@67ce08c7
*/
When above program is compiled following .class files are formed >
OuterClass.class > OuterClass
OuterClass$1LocalInnerClass.class >LocalInnerClass
InnerClassTest.class >InnerClassTest (Main class)
Program 1 for creating and using AnonymousInnerClass - And understanding how AnonymousInnerClass extend class>
class OuterClass{
void m(){
System.out.println("m()");
}
}
}
/*OUTPUT
overridden m()
*/
When above program is compiled following .class files are formed >
OuterClass.class > OuterClass
InnerClassTest$1.class >AnonymousInnerClass
InnerClassTest.class >InnerClassTest (Main class)
}.m();
}
}
/*OUTPUT
m()
*/
Program 4 to understand how AnonymousInnerClass can implement more than 2 interfaces >
Though, AnonymousInnerClass can implement more than one interface in following way >
Let’s create MyInterface which will extend Runnable interface. Now, AnonymousInnerClass will implement 2 interfaces.
interface MyInterface extends Runnable{
void m();
}
/**
* Main class
*/
public class InnerClassTest {
public static void main(String[] args) {
}
/*OUTPUT
implementation of MyInterface's m() method
*/
Differences between Instance initialization block and Static initialization block in java - Features in detail with programs
What are Instance initialization block & Static initialization block in java
Instance initialization block in java can be used to initialize instance variables in java.
Static initialization block in java can be used to initialize static variables in java.
class MyClass {
/* Static block */
static {
System.out.println("static block");
}
/* Non-Static block (Instance block) */
{
System.out.println("instance/non-static block");
}
/* Constructor */
MyClass() {
System.out.println("MyClass constructor");
}
}
public class BlockTest {
public static void main(String[] args) {
}
/*OUTPUT
static block
instance/non-static block
MyClass constructor
*/
Program 2 to show execution flow of static initialization blocks and instance initialization blocks when SuperClass and SubClasses are
used in java>
/**
* SuperClass
*/
class SuperClass {
/* Static block */
static {
System.out.println("SuperClass ----------> static block");
}
/* Non-Static block (Instance block) */
{
System.out.println("SuperClass ----------> Instance/non-static
block");
}
/* Constructor*/
SuperClass() {
System.out.println("SuperClass ----------> constructor");
}
}
/**
* SubClass
*/
class SubClass extends SuperClass {
/* Static block */
static {
System.out.println("SubClass > static block");
}
/* Non-Static block (Instance block) */
{
System.out.println("SubClass > Instance/non-static block");
}
/* Constructor*/
SubClass() {
System.out.println("SubClass > constructor");
}
}
public class BlockTest {
public static void main(String[] args) {
}
/*OUTPUT
SuperClass ----------> static block
SubClass > static block
SuperClass ----------> Instance/non-static block
SuperClass ----------> constructor
SubClass > Instance/non-static block
SubClass > constructor
*/
Known only as static initialization block in java. Also known as non-static initialization block in java.
static blocks executes before instance blocks in instance blocks executes after static blocks in java.
java.
Only static variables can be accessed inside Static and non-static variables (instance variables) can be accessed inside instance
static block block.
static blocks can be used for initializing static instance blocks can be used for initializing instance variables
variables or
or calling any instance method in java.
calling any static method in java.
static blocks executes when class is loaded in instance block executes only when instance of class is created, not called when class is
java. loaded in java.
this keyword cannot be used in static blocks. this keyword can be used in instance block.
Summary >
So in this core java tutorial we learned What are Instance initialization block & Static initialization block in java. Features of static
initialization block in java. Features of instance initialization block in java. Program to show instance initialization blocks executes
after static initialization blocks in java. Program to show execution flow of static initialization blocks and instance initialization
blocks when SuperClass and SubClasses are used in java. Difference between static initialization and instance initialization block in
java>
Q72. How ConcurrentHashMap works? Can 2 threads on same ConcurrentHashMap object access it concurrently ?
ConcurrentHashMap is divided into different segments based on concurrency level. So different threads can access different segments
concurrently.
16
Depending upon the level of concurrency required the concurrent HashMap is internally divided into segments. If the level of
concurrency required is not specified then it is takes 16 as the default value. So internally the ConcurrentHashMap will be divided into
16 segments. Each Segment behaves independently.
Null keys and HashMap allows to store one null key and many ConcurrentHashMap does not allow to store
values null values i.e. any key can have null value. null key or null value.
Any attempt to store null key or value throws
runtimeException (NullPointerException).
iterators The iterators returned by the iterator() method of iterators are fail-safe.
HashMap are fail-fast >
hashMap.keySet().iterator() concurrentHashMap.keySet().iterator()
hashMap.values().iterator() concurrentHashMap.values().iterator()
hashMap.entrySet().iterator() concurrentHashMap.entrySet().iterator()
all three iterators are fail-fast all three iterators are fail-safe.
putIfAbsent HashMap does not contain putIfAbsent method. If map does not contain specified key, put
putIfAbsent method is equivalent to writing specified key-value pair in map and return
following code > null.
If map already contains specified key, return
synchronized (map){ value corresponding to specified key.
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
}
Introduced in HashMap was introduced in java 2 i.e. JDK 1.2, ConcurrentHashMap was introduced in java 5
which java i.e. JDK 1.5, since its introduction Hashtable
version has become obsolete, because of concurrency
level its performance is better than Hashtable.
ConcurrentHashMap is divided into different segments based on concurrency level. So different threads can access different
segments concurrently in java.
For operations such as putAll concurrent retrievals may reflect removal of only some entries in java.
For operations such as clear concurrent retrievals may reflect removal of only some entries in java.
Now let’s form few questions to clear your doubts (based on above diagram) >
Question 1 : What will happen map.put(25,12) is called and some other thread concurrently calls map.get(25)?
Answer : When map.put(25,12) is called segment 2 will be locked,
key=25 also lies in segment 2, When thread locks one segment for updation it does not block it for retrieval hence some
other thread can read the same segment, but it will be able to read the data before locking (hence map.get(25) will return
121)
Question 2 : What will happen map.put(25,12) is called and some other thread concurrently calls map.get(33)?
Answer : When map.put(25,12) is called segment 2 will be locked,
key=33 also lies in segment 2, When thread locks one segment for updation it does not block it for retrieval hence some
other thread can read the same segment, but it will be able to read the data before locking (hence map.get(33) will return
15)
Question 3 : What will happen map.put(25,12) is called and some other thread concurrently calls map.put(33,24)?
Answer : When map.put(25,12) is called segment 2 will be locked,
key=33 also lies in segment 2, When thread locks one segment for updation it does not allow any other thread to perform
updations in same segment until lock is not released on segment.
hence map.put(33,24) will have to wait for map.put(25,12) operation to release lock on segment.
Question 4 : What will happen map.put(25,12) is called and some other thread concurrently calls map.put(30,29)?Answer :
When map.put(25,12) is called segment 2 will be locked, but key=30 lies in segment 3. Both the kays lies in different
segments, hence both operations can be performed concurrently.
Question 5 : What will happen updations (put/remove) are in process in certain segments and new key-pair have to be
put/remove in same segment ?
Answer : When updations are in process thread locks the segment and it does not allow any other thread to perform
updations (put/remove) in same segment until lock is not released on segment.
Let’s summarize above section >
What operations lock ConcurrentHashMap segment & what operations are allowed when ConcurrentHashMap segment is
locked >
thread locks one segment for updation (put/remove) & it does not block it for retrieval (get) hence some other
thread can read the same segment, but it will be able to read the data before locking
It’s important to know get operations does not lock any segment.
HashMap - can be synchronized by using Collections’s class synchronizedMap method in java.
Map synchronizedMap = Collections.synchronizedMap(hashMap);
Now, no 2 threads can access same instance of map concurrently.
Hence synchronized HashMap’s performance is slower as compared to ConcurrentHashMap in java.
Now let’s form few questions to clear your doubts (based on above diagram) >
Question 1 : What will happen map.put(25,12) is called and some other thread concurrently calls map.get(25)?
Answer : When map.put(25,12) is called whole map is locked, When one thread performs any updations (put/remove) on
HashMap it locks whole HashMap and does not allow any other thread to perform updation (put/remove) or retrieval (get)
operations until lock is not released on HashMap.
Hence map.get(25) operation will have to wait for map.put(25,12) operation to release lock on HashMap.
Insertion order HashMap and ConcurrentHashMap both does not maintain insertion order.
Implements java.util.Map HashMap and ConcurrentHashMap both are implementation of the java.util.Map interface.
Deadlock in multithreading - program to form DeadLock, solving DeadLock, measures to avoid Deadlock in java.
This is very important question from interview perspective. But, what makes this question important is it checks
interviewees capability of creating and detecting deadlock. If you can write a code to form deadlock, than I am sure you
must be well capable in solving that deadlock as well. If not, later on this post we will learn how to solve deadlock as well.
First question comes to mind is, what is deadlock in multi threading program?
Deadlock is a situation where two threads are waiting for each other to release lock holded by them on resources.
Thread-1 acquires lock on String.class and then calls sleep() method which gives Thread-2 the chance to execute
immediately after Thread-1 has acquired lock on String.class and Thread-2 acquires lock on Object.class then calls sleep()
method and now it waits for Thread-1 to release lock on String.class.
Conclusion:
Now, Thread-1 is waiting for Thread-2 to release lock on Object.class and Thread-2 is waiting for Thread-1 to release
lock on String.class and deadlock is formed.
Code called by Thread-1
synchronized (String.class) {
/*
* Adding this optional delay so that Thread-2 could enough time
* to lock Object class and form deadlock.
* If you remove this sleep, because of threads unpredictable
* behavior it might that Thread-1
* gets completed even before Thread-2 is started and we will
* never form deadLock.
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();}
synchronized (Object.class) {
System.out.println(Thread.currentThread().getName() + " has acquired "
+ "lock on Object class and waiting to acquire lock on String class...");
/*
* Adding this optional delay so that Thread-1 could enough
* time to lock String class and form deadlock.
* If you remove this sleep, because of threads unpredictable
* behavior it might that Thread-2
* gets completed even before Thread-1 is started and we
* will never form deadLock.
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();}
synchronized (String.class) {
System.out.println(Thread.currentThread().getName() +
" has acquired lock on String class");
}
}
Thread-2 has acquired lock on Object class and waiting to acquire lock on String class...
Thread-1 has acquired lock on String class and waiting to acquire lock on Object class...
*/
What happened in above program was Thread-1 was waiting for Thread-2 to release lock on Object.class and
Thread-2 was waiting for Thread-1 to release lock on String.class and deadlock was formed. One more crucial thing to
note down in output was " has ENDED" was never printed in output, because of deadlock Thread-1 & Thread-2 never ended.
Solving deadlock - Here comes the important part, how above formed deadlock could be solved :
Thread-1 acquires lock on String.class and then calls sleep() method which gives Thread-2 the chance to execute
immediately after Thread-1 has acquired lock on String.class and Thread-2 tries to acquire lock on String.class but lock is
holded by Thread-1. Meanwhile, Thread-1 completes successfully. As Thread-1 has completed successfully it releases lock
on String.class, Thread-2 can now acquire lock on String.class and complete successfully without any deadlock formation.
Conclusion: No deadlock is formed.
Code called by Thread-1
synchronized (String.class) {
//using Thread.sleep(100); // is optional.
System.out.println(Thread.currentThread().getName() + " has acquired lock "
+ "on String class and waiting to acquire lock on Object class...");
synchronized (Object.class) {
System.out.println(Thread.currentThread().getName()+" has acquired "
+ "lock on Object class");
}
}
synchronized (String.class) {
System.out.println(Thread.currentThread().getName()+" has acquired lock on "
+ "Object class and waiting to acquire lock on String class...");
synchronized (Object.class) {
System.out.println(Thread.currentThread().getName()+" has acquired "
+ "lock on String class");
}
}
Thread-1 has acquired lock on String class and waiting to acquire lock on Object class...
Thread-1 has acquired lock on Object class
Thread-1 has ENDED
Thread-2 has acquired lock on Object class and waiting to acquire lock on String class...
Thread-2 has acquired lock on String class
Thread-2 has ENDED
*/
What happened in above program was Thread-1 acquired lock on String.class and then called sleep() method which
gave Thread-2 the chance to execute immediately after Thread-1 acquired lock on String.class and then Thread-2 tried to
acquire lock on String.class but lock was holded by Thread-1. Meanwhile, Thread-1 completed successfully. As Thread-1
completed successfully it released lock on String.class, Thread-2 then acquired lock on String.class and completed
successfully. Hence, neither of the thread waited for each other to release locks and ended without any deadlock formation.
One more crucial thing to note down in output was " has ENDED" was printed in output, because Thread-1 & Thread-2
completed successfully.
1. Lock specific member variables of class rather than locking whole class: We must try to lock specific member
variables of class rather than locking whole class.
Example : Let’s say we have a class
class CustomClass{
Integer i;
String str;
}
Now rather than locking object of whole CustomClass try to lock specific fields which we want to synchronize.
Try to use such kind of locking (locking specific member variable of class) :
synchronized (customClassObj.str) {
}
Benefit of using such kind of locks is that any other thread can easily operate on unlocked member variable of class and
reduce risk of forming deadlock.
2. Use join() method: If possible try to use join() method, although it may refrain us from taking full advantage of
multithreading environment because threads will start and end sequentially, but it can be handy in avoiding deadlocks.
Now , I am going to provide you with source code to give you a better picture of how join() method can be handy in
avoiding deadlock in above used program.
synchronized (String.class) {
/*
* Adding this optional delay so that Thread-2 could enough time to lock Object class and form deadlock.
* If you remove this sleep, because of threads unpredictable behavior it might that Thread-1
* gets completed even before Thread-2 is started and we will never form deadLock.
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();}
synchronized (Object.class) {
System.out.println(Thread.currentThread().getName()+" has acquired lock on Object class and waiting to
acquire lock on String class...");
/*
* Adding this optional delay so that Thread-1 could enough time to lock String class and form deadlock.
* If you remove this sleep, because of threads unpredictable behavior it might that Thread-2
* gets completed even before Thread-1 is started and we will never form deadLock.
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();}
synchronized (String.class) {
System.out.println(Thread.currentThread().getName()+" has acquired lock on String class");
}
}
Thread-1 has acquired lock on String class and waiting to acquire lock on Object class...
Thread-1 has acquired lock on Object class
Thread-1 has ENDED
Thread-2 has acquired lock on Object class and waiting to acquire lock on String class...
Thread-2 has acquired lock on String class
Thread-2 has ENDED
*/
What happened in the above program was, because of join() method Thread-1 and Thread-2 started and ended sequentially.
Thread-1 was able to finish even before Thread-2 was started and no deadlock was formed.
synchronized (String.class) {
/*
* Adding this optional delay so that Thread-2 could enough time to lock Object class and form
deadlock.
* If you remove this sleep, because of threads unpredictable behavior it might that Thread-1
* gets completed even before Thread-2 is started and we will never form deadLock.
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();}
synchronized (Object.class) {
System.out.println(Thread.currentThread().getName()+" has acquired lock on Object class and waiting
to acquire lock on String class...");
/*
* Adding this optional delay so that Thread-1 could enough time to lock String class and form
deadlock.
* If you remove this sleep, because of threads unpredictable behavior it might that Thread-2
* gets completed even before Thread-1 is started and we will never form deadLock.
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {e.printStackTrace();}
synchronized (String.class) {
System.out.println(Thread.currentThread().getName()+" has acquired lock on String class");
}
}
Thread-2 has acquired lock on Object class and waiting to acquire lock on String class...
Thread-1 has acquired lock on String class and waiting to acquire lock on Object class...
*/
We can use following tools to generate thread dumps and find out root cause of deadlock by analyzing thread dumps.
VisualVM is most popular way to generate Thread Dump and is most widely used by developers. It’s important to understand usage of
VisualVM for in depth knowledge of VisualVM. I’ll recommend every developer must understand this topic to become master in multi
threading.
It helps us in analyzing threads performance, thread states, CPU consumed by threads, garbage collection and much more. For detailed
information see Generating and analyzing Thread Dumps using VisualVM - step by step detail to setup VisualVM with screenshots
jstack is very easy way to generate Thread dump and is widely used by developers. I’ll recommend every developer must understand this
topic to become master in multi threading. For creating Thread dumps we need not to download any jar or any extra software. For
detailed information see Generating and analyzing Thread Dumps using JSATCK - step by step detail to setup JSTACK with
screenshots.
Thread states/Thread life cycle is very basic question, before going deep into concepts we must understand Thread
life cycle. This post contains in depth explanation of thread methods explaining which method puts thread from
which state to which state.
New : When instance of thread is created using new operator it is in new state , but the start() method has not been
invoked on the thread yet, thread is not eligible to run yet.
>Thread object is considered alive but thread is not alive yet.
Running : Thread scheduler selects thread to go from runnable to running state. In running state Thread starts executing by
entering run() method.
>Thread scheduler selects thread from the runnable pool on basis of priority, if priority of two threads is same,
threads are scheduled in unpredictable manner. Thread scheduler behaviour is completely unpredictable.
>When threads are in running state, yield() method can make thread to go in Runnable state.
Suspend() method can be used to put thread in waiting state and resume() method is the only way which could put thread in
runnable state.
Thread also may go from running to waiting state if it is waiting for some I/O operation to take place. Once input is available
thread may return to running state.
Terminated (Dead) : A thread is considered dead when its run() method completes.
>Once thread is dead it cannot be started again doing so will throw runtimeException i.e.
IllegalThreadStateException.
Program to create daemon thread by using setDaemon() method and also use isDaemon() method to check whether thread is
daemon or not.
};
thread1.setDaemon(true); //setting thread to daemon.
System.out.println("is thread1 daemon thread : "
+thread1.isDaemon()); //checking thread isDeamon ?
thread1.start(); //start daemon thread
}
}
/*
is thread1 daemon thread : true
Thread-1 has started
Thread-1 has ended
*/
Program to show > if setDaemon(boolean on) is called on thread after calling start() method than
IllegalThreadStateException is thrown.
};
thread1.start(); //start daemon thread
thread1.setDaemon(true); //setting thread to daemon after start(), will throw IllegalThreadStateException.
}
}
/*
Thread-1 has started
Thread-1 has ended
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.setDaemon(Unknown Source)
at DaemonTestException.main(DaemonTestException.java:13)
*/
Should be called from synchronized block : wait() method is always called from synchronized block i.e.
wait() method needs to lock object monitor before object on which it is called. But sleep() method can be called from
outside synchronized block i.e. sleep() method doesn’t need any object monitor.
IllegalMonitorStateException : if wait() method is called without acquiring object lock than
IllegalMonitorStateException is thrown at runtime, but sleep() method never throws such exception.
Belongs to which class : wait() method belongs to java.lang.Object class but sleep() method belongs to
java.lang.Thread class.
Called on object or thread : wait() method is called on objects but sleep() method is called on Threads not
objects.
Thread state : when wait() method is called on object, thread that holded object’s monitor goes from
running to waiting state and can return to runnable state only when notify() or notifyAll() method is called on that
object. And later thread scheduler schedules that thread to go from from runnable to running state.
when sleep() is called on thread it goes from running to waiting state and can return to runnable state when sleep time
is up.
When called from synchronized block : when wait() method is called thread leaves the object lock. But sleep()
method when called from synchronized block or method thread doesn’t leaves object lock.
Definition : sleep() methods causes current thread to sleep for specified number of milliseconds (i.e. time
passed in sleep method as parameter). Ex- Thread.sleep(10) causes currently executing thread to sleep for 10 millisec.
Thread state : when sleep() is called on thread it goes from running to waiting state and can return to runnable
state when sleep time is up.
2. sleep(long millis, int nanos) - Causes the currently executing thread to sleep for the specified number of
milliseconds plus the specified number of nanoseconds.
static method : sleep() is a static method, causes the currently executing thread to sleep for the specified number
of milliseconds.
synchronized block : thread need not to to acquire object lock before calling sleep() method i.e. sleep() method
can be called from outside synchronized block.
*/
In the above program, main thread starts invokes Thread-1 and Thread-1 calls sleep method and it enters waiting state for
2000 millisec, meanwhile main thread gets chance to execute and finish. Once 2 seconds are over Thread-1 comes into
running state and finish its execution.
In the below program first main thread started, than it invoked Thread-1, then Thread-1 called sleep(100) method to ensure
that main thread don’t complete before Thread-1, than execution control went to main thread and it called
thread1.sleep(10000) but rather than putting Thread-1 on sleep it made main thread to sleep. And Thread-1 ended
before main thread.
class MyRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + " has started");
try {
Thread.sleep(100); //ensure that main thread don’t complete before Thread-1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " has ended");
}
}
public class SleepStatic {
public static void main(String... args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " has started");
Thread thread1 = new Thread(new MyRunnable(), "Thread-1");
thread1.start();
thread1.sleep(10000); //we will face warning - The static method
//sleep(long) from the type Thread should be accessed in a static way
System.out.println(Thread.currentThread().getName() + " has ended");
}
}
/*OUTPUT
main has started
Thread-1 has started
Thread-1 has ended
main has ended
*/
Wait() and notify() methods in java - Definition, 8 key features, solving consumer producer problem with & without
these methods and consequences of not using wait() and notify() methods.
notify() - Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of
them is chosen to be awakened. The choice is random and occurs at the discretion of the implementation. A thread waits on
an object's monitor by calling one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
notifyAll() - Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling
one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
wait() - Causes the current thread to wait until another thread invokes the notify() or notifyAll() method for this object.
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another
thread notifies threads waiting on this object's monitor to wake up either through a call to the notify()/ notifyAll() method.
The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
Thread state :
>By calling wait() method thread go from running to waiting state. In waiting state it will wait for other threads
to release object monitor/lock.
> Once notify() or notifyAll() method is called object monitor/lock becomes available and thread can again return to
runnable state.
synchronized block : thread needs to to acquire object lock before calling wait() and notify() methods i.e. these
methods can be called only from synchronized block or synchronized method.
Exception : As mentioned above before calling these methods thread must own object’s monitor means wait() and
notify() methods must be called from synchronized blocks or synchronized method otherwise IllegalMonitorStateException
is thrown at runtime.
Waiting time : wait() and notify() method have got few options.
1. wait() - It internally calls wait(0).
2. wait(long timeout) - Causes the current thread to wait until either another thread invokes the notify() or
notifyAll() methods for this object, or a specified timeout time has elapsed.
3. wait(long timeout, int nanos) - Causes the current thread to wait until either another thread invokes the
notify() or notifyAll() methods for this object, or a specified timeout time plus the specified number of
nanoseconds has elapsed.
Instance methods : wait() and notify() are instance methods and are always called on objects.
Native methods : implementation of wait() and notify() methods are provided by JVM.
Let’s see definition of wait() and notify() method as given in java.lang.Object -
public final void wait() throws InterruptedException
Belongs to which class : wait() and notify() methods belongs to java.lang.Object class.
Below i tried to give a very simple example to show usgae of wait() and notify() method to give you better understanding of
these methods.
Solve Consumer Producer problem by using wait() and notify() methods, where consumer can consume only when
production is over.
Producer will allow consumer to consume only when 10 products have been produced (i.e. when production is over).
Thought, we can solve this producer consumer problem without using wait() and notify() method as well, below i have
given consequences of not using using wait() and notify().
In program consumer thread will start() and wait by calling wait() method till producer is producing. Once
production is over, producer thread will call notify() method, which will notify consumer thread and consumer will
start consuming.
import java.util.ArrayList;
/* Producer is producing, Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
ArrayList<Integer> sharedQueue;
Producer(){
sharedQueue=new ArrayList<Integer>();
}
@Override
public void run(){
synchronized (this) {
for(int i=1;i<=10;i++){ //Producer will produce 10 products
sharedQueue.add(i);
System.out.println("Producer is still Producing, Produced : "+i);
try{
Thread.sleep(1000);
}catch(InterruptedException e){e.printStackTrace();}
}
System.out.println("Production is over, consumer can consume.");
this.notify(); //Production is over, notify consumer thread so that consumer can consume.
}
}
}
class Consumer extends Thread{
Producer prod;
Consumer(Producer obj){
prod=obj;
}
}
public class ProducerConsumerWithWaitNotify {
public static void main(String args[]) throws InterruptedException{
}
}
/*OUTPUT
Consumer waiting for production to get over.
Producer is still Producing, Produced : 1
Producer is still Producing, Produced : 2
Producer is still Producing, Produced : 3
Producer is still Producing, Produced : 4
Producer is still Producing, Produced : 5
Producer is still Producing, Produced : 6
Producer is still Producing, Produced : 7
Producer is still Producing, Produced : 8
Producer is still Producing, Produced : 9
Producer is still Producing, Produced : 10
Production is over, consumer can consume.
Consumed : 1
Consumed : 2
Consumed : 3
Consumed : 4
Consumed : 5
Consumed : 6
Consumed : 7
Consumed : 8
Consumed : 9
Consumed : 10
*/
But what could be consequences of not using using wait() and notify() to solve above producer consumer problem?
It will cost of us performance. Consumer thread will unnecessarily repeatedly check whether producer has completed
it’s production or not, but when wait() and notify() were used, consumer thread started, called wait() and waited for
producer thread to notify.
Let’s identify Problem statement in not using wait() and notify()>
while(this.prod.productionInProcess)
Using while loop is the actual problem statement in not using wait() and notify(), loops generally costs us performance and
we must try to avoid loops.
Let’ say producer was to producer 100 products and for every production it takes 10 seconds & consumer is checking after
every 20seconds whether production is over or not. In that case consumer will check after every every 2 products produced
whether production is over or not, unnecessary 50 calls will be made, which will of course slow down our whole process.
But now, let's solve above problem without using wait() and notify() - approach which won’t be performance friendly (but
provides developers a choice to solve producer consumer problem in different manner).
How to solve Consumer Producer problem without using wait() and notify() methods, where consumer can consume only
when production is over.
Producer will allow consumer to consume only when 10 products have been produced (i.e. when production is over).
We will approach by keeping one boolean variable productionInProcess and initially setting it to true, and later when
production will be over we will set it to false.
In program producer thread will start() and it will start producing and called sleep(1000) in between, which will give
consumer thread chance to execute. consumer checks whether productionInProcess is true or not, if it's true,
consumer will sleep(4000) and wake up after specified time and again check whether productionInProcess is true or
false. process will repeat till productionInProcess is true. Meanwhile, producer thread will complete production and
ultimately make productionInProcess to false. Once productionInProcess is false, consumer will consume.
import java.util.ArrayList;
/* Producer is producing, Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
boolean productionInProcess;
ArrayList<Integer> list;
Producer(){
productionInProcess=true; //initially Producer will be producing, so make this productionInProcess true.
list=new ArrayList<Integer>();
}
@Override
public void run(){
try{
Thread.sleep(1000);
}catch(InterruptedException e){e.printStackTrace();}
}
productionInProcess=false; // Once production is over, make this productionInProcess false.
//Production is over, consumer can consume.
}
class Consumer extends Thread{
Producer prod;
Consumer(Producer obj){
prod=obj;
}
}
public class ProducerConsumerWithoutWaitNotify {
public static void main(String args[]){
}
}
/*OUTPUT
Consumer waiting for production to get over.
Producer is still Producing, Produced : 1
Producer is still Producing, Produced : 2
Producer is still Producing, Produced : 3
Producer is still Producing, Produced : 4
Producer is still Producing, Produced : 5
Producer is still Producing, Produced : 6
Producer is still Producing, Produced : 7
Producer is still Producing, Produced : 8
Producer is still Producing, Produced : 9
Producer is still Producing, Produced : 10
Production is over, consumer can consume.
Consumed : 1
Consumed : 2
Consumed : 3
Consumed : 4
Consumed : 5
Consumed : 6
Consumed : 7
Consumed : 8
Consumed : 9
Consumed : 10
*/
Definition : yield() method when called on thread gives a hint to the thread scheduler that the current
thread is willing to yield its current use of a processor. The thread scheduler is free to ignore this hint. sleep()
methods causes current thread to sleep for specified number of milliseconds (i.e. time passed in sleep method as
parameter). Ex- Thread.sleep(10) causes currently executing thread to sleep for 10 millisec.
Thread state : when sleep() is called on thread it goes from running to waiting state and can return to runnable
state when sleep time is up. when yield() method is called on thread it goes from running to runnable state, not in
waiting state. Thread is eligible to run but not running and could be picked by scheduler at anytime.
Exception : yield() method doesn’t throws any exception. But sleep() method throws compile time exception
i.e. InterruptedException.
Waiting time : yield() method stops thread for unpredictable time, that depends on thread scheduler. But
sleep() method have got few options.
1. sleep(long millis) - Causes the currently executing thread to sleep for the specified number of
milliseconds
2. sleep(long millis, int nanos) - Causes the currently executing thread to sleep for the specified number of
milliseconds plus the specified number of nanoseconds.
> yield() and sleep() method can be called from outside synchronized block.
> yield() and sleep() method are called on Threads not objects.
Mention some guidelines to write thread safe code, most important point we must take care of in multithreading
programs?
In multithreading environment it’s important very important to write thread safe code, thread unsafe code can cause a major
threat to your application. I have posted many articles regarding thread safety. So overall this will be revision of what we
have learned so far i.e. writing thread safe healthy code and avoiding any kind of deadlocks.\
When we call start() method on thread, it internally calls run() method with newly created thread. So, if we don’t
override run() method newly created thread won’t be called and nothing will happen.
When we call start() method on thread, it internally calls run() method with newly created thread. So, if we override
start() method, run() method will not be called until we write code for calling run() method.
Can we acquire lock on class? What are ways in which you can acquire lock on class?
Yes, we can acquire lock on class’s class object in 2 ways to acquire lock on class.
Thread can acquire lock on class’s class object by-
1. Entering synchronized block
synchronized (MyClass.class) {
//thread has acquired lock on MyClass’s class object.
}
Or,
2. by entering static synchronized methods.
public static synchronized void method1() {
//thread has acquired lock on MyRunnable’s class object.
}
When one thread loops continuously waiting for another thread to signal.
Performance point of view - Busy spin is very bad from performance point of view, because one thread keeps on looping
continuously ( and consumes CPU) waiting for another thread to signal.
Guidelines to thread safe code, most important point we must take care of in multithreading programs
In multithreading environment it’s very important to write thread safe, thread unsafe code can cause a major threat to your
application. I have posted many articles regarding thread safety. So overall this article will be revision of what we have
learned so far i.e. writing thread safe healthy code and avoiding any kind of deadlocks.
1. If method is exposed in multithreading environment and it’s not synchronized (thread unsafe) than it might lead us
to race condition, we must try to use synchronized block and synchronized methods. Multiple threads may exist on same
object but only one thread of that object can enter synchronized method at a time, though threads on different object can
enter same method at same time.
2. Even static variables are not thread safe, they are used in static methods and if static methods are not synchronized
then thread on same or different object can enter method concurrently. Multiple threads may exist on same or
different objects of class but only one thread can enter static synchronized method at a time, we must consider
making static methods as synchronized.
3. If possible, try to use volatile variables. If a field is declared volatile all threads see a consistent value for the
variable. Volatile variables at times can be used as alternate to synchronized methods as well.
4. Final variables are thread safe because once assigned some reference of object they cannot point to reference of
other object.
5. Usage of local variables : If possible try to use local variables, local variables are thread safe, because every
thread has its own stack, i.e. every thread has its own local variables and its pushes all the local variables on stack.
6. We must avoid using deadlock prone deprecated thread methods such as destroy(), stop(), suspend() and
resume().
7. Using thread safe collections : Rather than using ArrayList we must Vector and in place of using HashMap we
must use ConcurrentHashMap or HashTable.
8. We must use VisualVM or jstack to detect problems such as deadlocks and time taken by threads to complete in
multi threading programs.
9. Using ThreadLocal : ThreadLocal is a class which provides thread-local variables. Every thread has its own
ThreadLocal value that makes ThreadLocal value threadsafe as well.
10. Rather than StringBuffer try using immutable classes such as String. Any change to String produces new String.
Difference between notify() and notifyAll() methods, with program
Theoretically you must have heard or you must be aware of differences between notify() and notifyAll().But have you
created program to achieve it? If not let’s do it.
First, I will like give you a brief description of what notify() and notifyAll() methods do.
notify() - Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of
them is chosen to be awakened. The choice is random and occurs at the discretion of the implementation. A thread waits on
an object's monitor by calling one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
public final native void notify();
notifyAll() - Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling
one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object.
Now it’s time to write down a program to prove the point >
I guess by this time you must be well capable or writing a program to show differences between notify() and notifyAll()
method. But did you saw above mentioned line ”The awakened threads will not be able to proceed until the current
thread relinquishes the lock on this object” . What does it mean?
It means when notify() method is called on object, thread notifies the other thread waiting on this object's monitor. But
thread does not immediately releases the object lock, it waits for synchronization block to complete.
synchronized (this) {
System.out.println(Thread.currentThread().getName()+" started");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class MyRunnable2 extends Thread{
MyRunnable1 myRunnable1;
MyRunnable2(MyRunnable1 MyRunnable1){
this.myRunnable1=MyRunnable1;
}
synchronized (this.myRunnable1) {
System.out.println(Thread.currentThread().getName()+ " started");
try {
this.myRunnable1.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" has been notified");
}
}
}
class MyRunnable3 extends Thread{
MyRunnable1 myRunnable1;
MyRunnable3(MyRunnable1 MyRunnable1){
this.myRunnable1=MyRunnable1;
}
}
}
t1.start();
t2.start();
Thread.sleep(100); //Used to ensure that thread1 and thread2 starts before thread-3
//because thread-1 and 2 calls wait(), while thread-3 calls notify or notifyAll()
t3.start();
}
}
/* OUTPUT with notify()
Thread-1 started
Thread-2 started
Thread-3 started
Thread-3 has notified waiting threads
Thread-1 has been notified
*/
/* OUTPUT with notifyAll()
Thread-1 started
Thread-2 started
Thread-3 started
Thread-3 has notified waiting threads
Thread-1 has been notified
Thread-2 has been notified
*/
This question will test your basic knowledge how start and run methods work internally in Thread Api.
When we call start() method on thread, it internally calls run() method with newly created thread. So, if we don’t
override run() method newly created thread won’t be called and nothing will happen.
This question will again test your basic core java knowledge how overriding works at runtime, what will be called at runtime
and how start and run methods work internally in Thread Api.
When we call start() method on thread, it internally calls run() method with newly created thread. So, if we override
start() method, run() method will not be called until we write code for calling run() method.
@Override
public void start(){
System.out.println("In start() method");
}
}
public class OverrideStartMethod {
public static void main(String[] args) {
System.out.println("main has started.");
Class Level Lock:- Its mainly used to make static level data thread safe…..
Object level Lock:- This can always be done to make instance-level data thread-safe.
1) First let’s acquire lock on class’s class object by entering synchronized block.
Let’s say there is one class MyClass. Now we can create synchronization block, and parameter passed with synchronization
tells which class has to be synchronized. In below code, we have synchronized MyClass
synchronized (MyClass.class) {
//thread has acquired lock on MyClass’s class object.
}
As soon as thread entered Synchronization block, thread acquired MyClass’s class object. Thread will leave lock when it
exits synchronized block.
It’s important to know that multiple objects of class may exist but there is always one class’s class object lock available.
}
}
/*OUTPUT
0 Thread-1 is executing
1 Thread-1 is executing
2 Thread-1 is executing
3 Thread-1 is executing
4 Thread-1 is executing
0 Thread-2 is executing
1 Thread-2 is executing
2 Thread-2 is executing
3 Thread-2 is executing
4 Thread-2 is executing
*/
If you note output, Thread-1 entered synchronized block and was holding lock on MyClass’s class object. So, Thread-2
waited for Thread-1 to release lock on MyClass’s class object so that it could enter synchronized block.
As soon as thread entered Synchronization method, thread acquired lock on class’s class object.
Thread will leave lock when it exits static synchronized method.
It’s important to know that multiple threads may exist on same or different objects of class but only one thread can enter
static synchronized method at a time.
}
public static synchronized void method1(){
for(int i=0;i<5;i++){
System.out.println(i+" "+Thread.currentThread().getName()+" is
executing");
try {
Thread.sleep(500);
} catch (InterruptedException e) {e.printStackTrace(); }
}
}
}
public class MyClass {
public static void main(String args[]) throws InterruptedException{
MyRunnable object1=new MyRunnable();
MyRunnable object2=new MyRunnable();
}
}
/*OUTPUT
0 Thread-1 is executing
1 Thread-1 is executing
2 Thread-1 is executing
3 Thread-1 is executing
4 Thread-1 is executing
0 Thread-2 is executing
1 Thread-2 is executing
2 Thread-2 is executing
3 Thread-2 is executing
4 Thread-2 is executing
*/
If you note output, Thread-1 entered static synchronized method and was holding lock on MyRunnable’s class object. So,
Thread-2 waited for Thread-1 to release lock on MyRunnable’s class object so that it could enter static synchronized
method.
But, it may also happen that Thread-2 might enter static synchronized method first and in that case output will be -
/*OUTPUT
0 Thread-2 is executing
1 Thread-2 is executing
2 Thread-2 is executing
3 Thread-2 is executing
4 Thread-2 is executing
0 Thread-1 is executing
1 Thread-1 is executing
2 Thread-1 is executing
3 Thread-1 is executing
4 Thread-1 is executing
*/
If you note output, Thread-2 entered static synchronized method and was holding lock on MyRunnable’s class object. So,
Thread-1 waited for Thread-2 to release lock on MyRunnable’s class object so that it could enter static synchronized
method.
It is very important multithreading topic. We must understand this difference to answer interview, ocjp answers correctly.
Thread can acquire object lock by- Thread can acquire lock on class’s class object by-
1. Entering synchronized block or 1. Entering synchronized block or
2. by entering synchronized methods. 2. by entering static synchronized methods.
Multiple threads may exist on same object but only one thread of Multiple threads may exist on same or different
that object can enter synchronized method at a time. objects of class but only one thread can enter static
synchronized method at a time.
Threads on different object can enter same method at same time.
Multiple objects of class may exist and every object has it’s Multiple objects of class may exist but there is
own lock. always one class’s class object lock available.
First let’s acquire object lock by entering synchronized block. First let’s acquire lock on class’s class object by
entering synchronized block.
Example- Let’s say there is one class MyClass and we have
created it’s object and reference to that object is myClass. Now Example- Let’s say there is one class MyClass. Now
we can create synchronization block, and parameter passed with we can create synchronization block, and parameter
synchronization tells which object has to be synchronized. In passed with synchronization tells which class has to
below code, we have synchronized object reference by myClass. be synchronized. In below code, we have
MyClass myClass=new Myclass(); synchronized MyClass
synchronized (myClass) { synchronized (MyClass.class) {
} }
As soon thread entered Synchronization block, thread acquired
object lock on object referenced by myClass (by acquiring As soon as thread entered Synchronization block,
object’s monitor.) thread acquired MyClass’s class object. Thread will
Thread will leave lock when it exits synchronized block. leave lock when it exits synchronized block.
What is ThreadPool?
ThreadPool is a pool of threads which reuses a fixed number of threads to execute tasks.
At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all
threads are active, they will wait in the queue until a thread is available.
ThreadPool implementation internally uses LinkedBlockingQueue for adding and removing tasks.
In this post i will be using custom LinkedBlockingQueue, you can refer this post for implementing ThreadPool using Java
Api’s LinkedBlockingQueue & also for more detailed information on ThreadPool.
if(this.threadPool.isPoolShutDownInitiated() &&
this.taskQueue.size()==0)
this.interrupt();
}
...
}
package ThreadPoolUsingLinkedBlockingQueueCustom;
import java.util.LinkedList;
import java.util.List;
/**
* Implementing custom BlockingQueue interface .
* This BlockingQueue implementation follows FIFO (first-in-first-out).
* New elements are inserted at the tail of the queue,
* and removal elements is done at the head of the queue.
*
* @author AnkitMittal
* Copyright (c), AnkitMittal .
* All Contents are copyrighted and must not be reproduced in any form.
*/
interface BlockingQueueCustom<E> {
/**
* Inserts the specified element into this queue
* only if space is available else
* waits for space to become available.
*/
void put(E item) throws InterruptedException ;
/**
* Retrieves and removes the head of this queue
* only if elements are available else
* waits for element to become available.
*/
E take() throws InterruptedException;
/**
* Returns size of queue.
*/
int size();
}
/**
* Implementing custom LinkedBlockingQueue class.
* This BlockingQueue implementation follows FIFO (first-in-first-out).
* New elements are inserted at the tail of the queue,
* and removal elements is done at the head of the queue.
*
* @author AnkitMittal
* Copyright (c), AnkitMittal .
* All Contents are copyrighted and must not be reproduced in any form.
*/
class LinkedBlockingQueueCustom<E> implements BlockingQueueCustom<E>{
private List<E> queue;
private int maxSize ; //maximum number of elements queue can hold at a time.
public LinkedBlockingQueueCustom(int maxSize){
this.maxSize = maxSize;
queue = new LinkedList<E>();
}
/**
* Inserts the specified element into this queue
* only if space is available else
* waits for space to become available.
* After inserting element it notifies all waiting threads.
*/
public synchronized void put(E item) throws InterruptedException {
}
/**
* Returns size of LinkedBlockingQueueCustom.
*/
public synchronized int size() {
return queue.size();
}
}
/**
* ThreadPool is a class which creates a thread pool that reuses a fixed
* number of threads to execute tasks.
* At any point, at most nThreads threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
*
* Once shutdown of ThreadPool is initiated, previously submitted tasks are
* executed, but no new tasks will be accepted.
*
* @author AnkitMittal
* Copyright (c), AnkitMittal .JavaMadeSoEasy.com
* All Contents are copyrighted and must not be reproduced in any form.
*/
class ThreadPool {
private BlockingQueueCustom<Runnable> taskQueue;
/*
* Once pool shutDown will be initiated, poolShutDownInitiated will become true.
*/
private boolean poolShutDownInitiated = false;
/* Constructor of ThreadPool
* nThreads= is a number of threads that exist in ThreadPool.
* nThreads number of threads are created and started. *
*/
public ThreadPool(int nThreads){
taskQueue = new LinkedBlockingQueueCustom<Runnable>(nThreads);
//Create and start nThreads number of threads.
for(int i=1; i<=nThreads; i++){
ThreadPoolsThread threadPoolsThread=new ThreadPoolsThread(taskQueue,this);
threadPoolsThread.setName("Thread-"+i);
System.out.println("Thread-"+i +" created in ThreadPool.");
threadPoolsThread.start(); //start thread
}
/**
* Execute the task, task must be of Runnable type.
*/
public synchronized void execute(Runnable task) throws Exception{
if(this.poolShutDownInitiated)
throw new Exception("ThreadPool has been shutDown, no further tasks can be added");
/*
* Add task in sharedQueue,
* and notify all waiting threads that task is available.
*/
System.out.println("task has been added.");
this.taskQueue.put(task);
}
public boolean isPoolShutDownInitiated() {
return poolShutDownInitiated;
}
/**
* Initiates shutdown of ThreadPool, previously submitted tasks
* are executed, but no new tasks will be accepted.
*/
public synchronized void shutdown(){
this.poolShutDownInitiated = true;
System.out.println("ThreadPool SHUTDOWN initiated.");
}
}
/**
* These threads are created and started from constructor of ThreadPool class.
*/
class ThreadPoolsThread extends Thread {
private BlockingQueueCustom<Runnable> taskQueue;
private ThreadPool threadPool;
public ThreadPoolsThread(BlockingQueueCustom<Runnable> queue,
ThreadPool threadPool){
taskQueue = queue;
this.threadPool=threadPool;
}
public void run() {
try {
/*
* ThreadPool's threads will keep on running
* until ThreadPool is not shutDown (shutDown will interrupt thread) and
* taskQueue contains some unExecuted tasks.
*/
while (true) {
System.out.println(Thread.currentThread().getName()
+" is READY to execute task.");
/*ThreadPool's thread will take() task from sharedQueue
* only if tasks are available else
* waits for tasks to become available.
*/
Runnable runnable = taskQueue.take();
System.out.println(Thread.currentThread().getName()
+" has taken task.");
//Now, execute task with current thread.
runnable.run();
System.out.println(Thread.currentThread().getName()
+" has EXECUTED task.");
/*
* 1) Check whether pool shutDown has been initiated or not,
* if pool shutDown has been initiated and
* 2) taskQueue does not contain any
* unExecuted task (i.e. taskQueue's size is 0 )
* than interrupt() the thread.
*/
if(this.threadPool.isPoolShutDownInitiated()
&& this.taskQueue.size()==0){
this.interrupt();
/*
* Interrupting basically sends a message to the thread
* indicating it has been interrupted but it doesn't cause
* a thread to stop immediately,
*
* if sleep is called, thread immediately throws
* InterruptedException
*/
Thread.sleep(1);
}
}
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+" has been STOPPED.");
}
}
}
/**
* Task class which implements Runnable.
*/
class Task implements Runnable{
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()
+" is executing task.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
/**
* Test ThreadPool.
*/
public class ThreadPoolTest{
public static void main(String[] args) throws Exception {
ThreadPool threadPool=new ThreadPool(2); //create 2 threads in ThreadPool
Runnable task=new Task();
threadPool.execute(task);
threadPool.execute(task);
threadPool.shutdown();
}
/*OUTPUT
Thread-1 created in ThreadPool.
Thread-2 created in ThreadPool.
Thread-1 is READY to execute task.
Thread-2 is READY to execute task.
task has been added.
task has been added.
Thread-1 has taken task.
Thread-2 has taken task.
ThreadPool SHUTDOWN initiated.
Thread-1 is executing task.
Thread-1 has EXECUTED task.
Thread-1 has been STOPPED.
Thread-2 is executing task.
Thread-2 has EXECUTED task.
Thread-2 has been STOPPED.
*/
Let’s discuss output in detail, to get better understanding of ThreadPool program >
Note : I have mentioned output in green text.
What is ThreadLocal ?
ThreadLocal is a class which provides thread-local variables. Every thread has its own ThreadLocal value that makes
ThreadLocal value threadsafe as well.
Application of ThreadLocal?
1. ThreadLocal are used by many web frameworks for maintaining some context (may be session or request)
related value.
o In any single threaded application, same thread is assigned for every request made to same action, so
ThreadLocal values will be available in next request as well.
o In multi threaded application, different thread is assigned for every request made to same action, so
ThreadLocal values will be different for every request.
2. When threads have started at different time they might like to store time at which they have started. So, thread’s
start time can be stored in ThreadLocal.
Creating ThreadLocal >
We will create instance of ThreadLocal. ThreadLocal is a generic class, i will be using String to demonstrate threadLocal.
All threads will see same instance of ThreadLocal, but a thread will be able to see value which was set by it only.
threadLocal.get()
threadLocal.remove();
Thread can remove value of ThreadLocal by calling remove() method on threadLocal. Once value has been removed get()
method will return null.
import java.util.Date;
public class ThreadLocalUsage {
public static class MyRunnable implements Runnable {
private ThreadLocal<String> threadLocal = new
ThreadLocal<String>();
@Override
public void run() {
threadLocal.set(new Date().toString());
try {
Thread.sleep(4000);
} catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName()+
" start time = "+threadLocal.get());
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable,"Thread-1");
Thread thread2 = new Thread(myRunnable,"Thread-2");
thread1.start();
Thread.sleep(1000); //Start thread-2 after 1 second.
thread2.start();
}
}
/*OUTPUT
Thread-1 start time = Sun Mar 08 4:08:43 IST 2015
Thread-2 start time = Sun Mar 08 4:08:44 IST 2015
*/
In the program, Thread-1 started and after 1 second Thread-2 also started.
Thread-1 called threadLocal.set(new Date().toString()) and set the threadLocal value i.e. value when thread was started
and then went for sleep.
Than, Thread-2 called threadLocal.set(new Date().toString()) and set the threadLocal value i.e. value when thread was
started and then went for sleep.
When both the threads waked up they called threadLocal.get() and we saw that both threads were having different
threadLocal value i.e. time at which they started.
Conclusion : Thread-1 and Thread-2 were having different threadLocal value.
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+
" start time = "+threadLocal.get());
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable,"Thread-1");
thread1.start();
}
}
/*OUTPUT
Thread-1 start time = Sun Mar 08 4:25:20 IST 2015
*/
What will happen if ThreadLocal was replaced with some other object in above program>
If ThreadLocal is replaced with some other object let’s say String than both the threads will hold same value for threadLocal.
import java.util.Date;
public class ThreadLocalReplaceWithString {
public static class MyRunnable implements Runnable {
private String threadLocal = new String("");
@Override
public void run() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName()+
" start time = "+threadLocal);
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable,"Thread-1");
Thread thread2 = new Thread(myRunnable,"Thread-2");
thread1.start();
Thread.sleep(1000); //Start thread-2 after 1 second.
thread2.start();
}
}
/*OUTPUT
Thread-1's start time = Sun Mar 08 4:33:00 IST 2015
Thread-2's start time = Sun Mar 08 4:33:00 IST 2015
*/
ThreadLocal was replaced with String.
Thread-1’s threadLocal value was overridden by Thread-2’s threadLocal value. So, threadLocal printed same start time for
both threads.
Busy Spin - What is busy spin? Consumer Producer problem with busy spin and solution to busy spin in java.
Performance point of view - Busy spin is very bad from performance point of view, because one thread keeps on looping
continuously ( and consumes CPU) waiting for another thread to signal.
Why using wait() and notify() is much better option to solve busy spin?
Because in case when we use sleep() method, thread will wake up again and again after specified sleep time until boolean
variable is true. But, in case of wait() thread will wake up only when when notified by calling notify() or notifyAll(), hence
end up consuming CPU in best possible manner
Note: In below program, Producer will allow consumer to consume only when 10 products have been produced (i.e. when
production is over)
Consumer thread continuously execute (busy spin) in while loop (till productionInProcess is true) and wait for producer
thread to get over. Once producer thread has ended it will make boolean variable productionInProcess false and busy spin
will be over.
while(this.prod.productionInProcess){
System.out.println("BUSY SPIN - Consumer waiting for production to get over");
}
import java.util.ArrayList;
/* Producer will allow consumer to
* consume only when 10 products have been produced (i.e. when production is over).
*/
class Producer implements Runnable{
boolean productionInProcess;
ArrayList<Integer> list;
Producer(){
productionInProcess=true; //initially Producer will be producing, so
//make this productionInProcess true.
list=new ArrayList<Integer>();
}
@Override
public void run(){
try{
Thread.sleep(500);
}catch(InterruptedException e){e.printStackTrace();}
}
productionInProcess=false; // Once production is over, make
//this productionInProcess false.
//Production is over, consumer can consume.
}
class Consumer extends Thread{
Producer prod;
Consumer(Producer obj){
prod=obj;
}
}
public class BusySpin{
public static void main(String args[]){
}
}
If we execute this program we will note in output that "BUSY SPIN - Consumer waiting for production to get over.” is
printed several times.
Executor and ExecutorService framework in java - Detailed explanation with full program
Executor and ExecutorService are used for following purposes in java >
creating thread,
starting threads,
managing whole life cycle of Threads.
Executor creates pool of threads and manages life cycle of all threads in it in java.
An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of
one or more asynchronous tasks in java.
void shutdown()
Initiates shutdown of executor, previously submitted tasks are executed, but no new tasks will be accepted in java.
List<Runnable> shutdownNow()
executor shutDowns immediately,
all actively executing tasks are stopped,
awaiting tasks will never execute, and
method returns list all tasks that were awaiting execution in java.
boolean isTerminated()
Method returns true if all tasks have completed following shut down in java.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable implements Runnable {
int taskNumber;
MyRunnable(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " executing task no " + taskNumber);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.1) Let’s discuss output in detail, to get better understanding of Executor and ExecutorService usage in program in java >
Note : I have mentioned output in green text.
2 threads in executor will be used for executing 10 tasks. So, at a time only 2 tasks will be executed
2 created threads in executor will be used for executing 10 tasks. So, at a time only 2 tasks will be executed.
If we analyze output at runtime we will notice that at a time only 2 tasks were executed.
So far in this thread concurrency tutorial we have learned what is Executor and ExecutorService framework in java with
program and examples. Now we will learn what are Future and Callable in java.
4) java.util.concurrent.Future<V> in java
Future interface provides methods in java >
for returning result of computation, wait until computation is not completed and
for cancelling the computation in between in java.
cancel method
method cancels the task.
5) java.util.concurrent.Callable<V> in java
Callable interface provides method for computing a result and returning that computed result or throws an exception if
unable to do so
Any class implementing Callable interface must override call() method.
This Future object can check the status of a Callable call’s method and wait until Callable’s call() method is not completed.
executor.shutdown();
}
}
/*OUTPUT
SumIntegerCallable has returned > 10
SquareDoubleCallable has returned > 4.840000000000001
*/
In the above program - we submit a Callable object to an Executor and returned object was of Future type.
8) Using <T> Future<T> submit(Runnable task, T result) and Future<?> submit(Runnable task) in program in java >
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable's run()");
}
}
public class SubmitRunnableExample {
private static final int NTHREDS = 10;
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
Future<Integer> futureInteger=executor.submit(new MyRunnable(), 1);
System.out.println("futureInteger.get() > "+futureInteger.get());
when executor.submit(new MyRunnable()) was called, it internally called call() method and on successful completion of
MyRunnable’s run() method, futureInteger.get() returned null.
9) Differences between execute() and submit() method of executor framework in thread concurrency in java >
It can be used for executing It can be used for executing runnable task or callable task, submitted callable
runnable task. returns future and Future's get method will return the task's result.
In this thread concurrency tutorial we will learn what is java.util.concurrent.Semaphore in java with program and examples.
We will learn about Semaphore constructors, what is permits, Semaphore’s important method like acquire and release in
thread concurrency in java. We will learn Application of Semaphore in real world (for solving Producer Consumer problem)
}
}
public IncrementThread(Semaphore s) {
semaphore=s;
}
for(int i=0;i<5;i++){
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+
" > "+SemaphoreExample.SharedValue++);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
" has released permit");
semaphore.release();
}
class DecrementThread implements Runnable{
Semaphore semaphore;
public DecrementThread(Semaphore s){
semaphore=s;
}
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+
" has got permit");
for(int i=0;i<5;i++){
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+
" >"+SemaphoreExample.SharedValue--);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
" has released permit");
semaphore.release();
}
/*OUTPUT
Let’s discuss output in detail, to get better understanding of Semaphore usage in program in java >
Note : I have mentioned output in green text.
incrementThread > 0
incrementThread > 1
incrementThread > 2
incrementThread > 3
incrementThread > 4
incrementThread continues to increment SemaphoreExample.SharedValue
decrementThread >5
decrementThread >4
decrementThread >3
decrementThread >2
decrementThread >1
incrementThread continues to decrement SemaphoreExample.SharedValue
3) Application of Semaphore in real world (for solving Producer Consumer problem in java) >
But how Semaphore can be used for implementing Producer Consumer pattern?
Semaphore on producer is created with permit =1. So, that producer can get the permit to produce.
Semaphore on consumer is created with permit =0. So, that consumer could wait for permit to consume. [because
initially producer hasn’t produced any product]
Producer gets permit by calling semaphoreProducer.acquire() and starts producing, after producing it calls
semaphoreConsumer.release(). So, that consumer could get the permit to consume.
semaphoreProducer.acquire();
System.out.println("Produced : "+i);
semaphoreConsumer.release();
Consumer gets permit by calling semaphoreConsumer.acquire() and starts consuming, after consuming it calls
semaphoreProducer.release(). So, that producer could get the permit to produce.
semaphoreConsumer.acquire();
System.out.println("Consumed : "+i);
semaphoreProducer.release();
For more detailed information on how Semaphore can be used for implementing Producer Consumer pattern, please refer my
next tutorial.
4) Program - If permits are 0, then acquire() method can acquire lock only when release() method is called in java.
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(0);
new Thread(new MyRunnable(semaphore),"Thread-1").start();
}
}
class MyRunnable implements Runnable{
Semaphore semaphore;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*OUTPUT
Thread-1 is waiting for permit
*/
1) Logic behind using Semaphore for implementing Producer Consumer pattern >
Semaphore on producer is created with permit =1. So, that producer can get the permit to produce.
Semaphore on consumer is created with permit =0. So, that consumer could wait for permit to consume. [because
initially producer hasn’t produced any product]
Producer gets permit by calling semaphoreProducer.acquire() and starts producing, after producing it calls
semaphoreConsumer.release(). So, that consumer could get the permit to consume.
semaphoreProducer.acquire();
System.out.println("Produced : "+i);
semaphoreConsumer.release();
Consumer gets permit by calling semaphoreConsumer.acquire() and starts consuming, after consuming it calls
semaphoreProducer.release(). So, that producer could get the permit to produce.
semaphoreConsumer.acquire();
System.out.println("Consumed : "+i);
semaphoreProducer.release();
2) Program to demonstrate usage of Semaphore for implementing Producer Consumer pattern >
import java.util.concurrent.Semaphore;
Semaphore semaphoreProducer;
Semaphore semaphoreConsumer;
public Producer(Semaphore semaphoreProducer,Semaphore semaphoreConsumer) {
this.semaphoreProducer=semaphoreProducer;
this.semaphoreConsumer=semaphoreConsumer;
}
public void run() {
for(int i=1;i<=5;i++){
try {
semaphoreProducer.acquire();
System.out.println("Produced : "+i);
semaphoreConsumer.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* Consumer Class.
*/
class Consumer implements Runnable{
Semaphore semaphoreConsumer;
Semaphore semaphoreProducer;
for(int i=1;i<=5;i++){
try {
semaphoreConsumer.acquire();
System.out.println("Consumed : "+i);
semaphoreProducer.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*OUTPUT
semaphoreProducer permit=1 | semaphoreConsumer permit=0
Produced : 1
Consumed : 1
Produced : 2
Consumed : 2
Produced : 3
Consumed : 3
Produced : 4
Consumed : 4
Produced : 5
Consumed : 5
*/
Let’s discuss output in detail, to get better understanding of how we have used Semaphore for implementing Producer
Consumer pattern >
Note : (I have mentioned output in green text and it’s explanation is given in line immediately followed by it)
semaphoreProducer permit=1 | semaphoreConsumer permit=0
semaphoreProducer created with permit=1. So, that producer can get the permit to produce |
semaphoreConsumer created with permit=0. So, that consumer could wait for permit to consume.
semaphoreProducer.acquire() is called, Producer has got the permit and it can produce [Now, semaphoreProducer permit=0]
Produced : 1 [as producer has got permit, it is producing]
semaphoreConsumer.release() is called, Permit has been released on semaphoreConsumer means consumer can consume
[Now, semaphoreConsumer permit=1]
semaphoreConsumer.acquire() is called, Consumere has got the permit and it can consume [Now, semaphoreConsumer
permit=0]
Consumed : 1 [as consumer has got permit, it is consuming]
semaphoreProducer.release() is called, Permit has been released on semaphoreProducer means producer can produce [Now,
semaphoreProducer permit=1]
Produced : 2
Consumed : 2
Produced : 3
Consumed : 3
Produced : 4
Consumed : 4
Produced : 5
Consumed : 5
Summary >
In previous thread concurrency tutorial we learned what is java.util.concurrent.Semaphore in java. And in this thread
concurrency tutorial we learned application of Semaphore in real world (for solving Producer Consumer problem in java).
Let’s start by understanding what is Serialization, it’s most basic question which you will have to answer almost in each and every java
interview.
Serialization is process of converting object into byte stream.
Serialized object (byte stream) can be:
>Transferred over network.
>Persisted/saved into file.
>Persisted/saved into database.
Once, object have been transferred over network or persisted in file or in database, we could deserialize the object and retain its state as it is
in which it was serialized.
Q106. How can you avoid certain member variables of class from getting Serialized?
Mark member variables as static or transient, and those member variables will no more be a part of Serialization.
Q107. What is serialVersionUID? What will be impact of not defining serialVersionUID in class?
This is one my favourite question, The serialization at runtime associates with each serializable class a version number, called a
serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for
that object that are compatible with respect to serialization.
If we don’t define serialVersionUID in the class, and any modification is made in class, then we won’t be able to deSerialize our class
because serialVersionUID generated by java compiler for modified class will be different from old serialized object . And
deserialization process will end up throwing java.io.InvalidClassException (because of serialVersionUID mismatch)
Q109. What will happen if one the member of class does not implement Serializable interface (Important)?
This is classy question which will check your in depth knowledge of Serialization concepts. If any of the member does not implement
Serializable than NotSerializableException is thrown. Now, let’s see a program.
Q110. What will happen if we have used List, Set and Map as member of class?
This question which will check your in depth knowledge of Serialization and Java Api’s. ArrayList, HashSet and HashMap implements
Serializable interface, so if we will use them as member of class they will get Serialized and DeSerialized as well. Now, let’s see a program.
Question 112. Is constructor of super class called during DeSerialization process of subclass?
Again your basic java concepts will be tested over here. It is depends on whether our superclass has implemented Serializable or not.
If superclass has implemented Serializable - constructor is not called during DeSerialization process.
If superclass has not implemented Serializable - constructor is called during DeSerialization process.
Q113. How you can avoid Deserialization process creating another instance of Singleton class?
This is another classy and very important question which will check your in depth knowledge of Serialization and Singleton concepts. I’ll
prefer you must understand this concept in detail. We can simply use readResolve() method to return same instance of class, rather than
creating a new one.
Q114. How can subclass avoid Serialization if its superClass has implemented Serialization interface ?
If superClass has implemented Serializable that means subclass is also Serializable (as subclass always inherits all features from its
parent class), for avoiding Serialization in sub-class we can define writeObject() method and throw NotSerializableException().
private void writeObject(ObjectOutputStream os) throws NotSerializableException
{
throw new NotSerializableException("This class cannot be Serialized");
}
In this thread concurrency tutorial we will learn what are Atomic operations in java with program and examples. We will learn how to
perform Atomic operations in thread concurrency in java. We will learn about different atomic classes like AtomicInteger, AtomicLong
and AtomicBoolean in java.
3) Why Classes like AtomicByte, AtomicShort, AtomicFloat, AtomicDouble and AtomicCharacter are not found in java (till java 8)
>
AtomicByte, AtomicShort, AtomicFloat, AtomicDouble and AtomicCharacter are present in java (till java 8) because these primitive types
like byte, short, float, double are not used too much as compared to int and long in java. So, there is no point of making concurrent classes
on top of these primitive types. Although this does not conclude to any concrete reason of their absence in java. You never know they might
be introduced in later versions of java.
We will learn important methods of AtomicInteger like getAndSet, incrementAndGet, getAndAdd, getAndIncrement,
decrementAndGet, getAndDecrement and how to use them in thread concurrency in java.
Example >
AtomicInteger atomicInteger =new
AtomicInteger();
We have created a new AtomicInteger and it is initialized to 0.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
We have created a new AtomicInteger and it is initialized to 11.
int get()
method returns the current value in java
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.get();
Method will return 11.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.set(12);
Method will set return atomicInteger to 12.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.getAndSet(12);
Method will set return atomicInteger to 12. And return 11.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.addAndGet(4);
adds 4 to the current value. And return 15.
int incrementAndGet()
increments current value by 1. And return updated value.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.incrementAndGet();
increments current value by 1. And return 12.
int getAndIncrement()
Method return current value. And increments current value by 1.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.getAndIncrement();
Method return 11. And increments 11 by 1.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.decrementAndGet();
decrements current value by 1. And return 10.
int getAndDecrement()
Method return current value. And decrements current value by 1.
Example >
AtomicInteger atomicInteger =new
AtomicInteger(11);
atomicInteger.getAndDecrement();
Method return 11. And decrements 11 by 1.
2) Example/Program to demonstrate usage of java.util.concurrent.atomic.AtomicInteger in java>
package AtomicInteger;
import java.util.concurrent.atomic.AtomicInteger;
class MyRunnable implements Runnable{
}
}
public class AtomicIntegerExample {
//Create a new AtomicInteger and is initialized to 0.
static AtomicInteger sharedAtomicInteger =new AtomicInteger();
sharedAtomicInteger is incremented atomically, but sysout statements have executed out of order.
3) Program to show Consequences of using Integer in place of AtomicInteger in java >
class MyRunnable implements Runnable{
System.out.println("ThreadName="+Thread.currentThread().getName()
+" > "+
++sharedIntegerExample.sharedInteger);
}
}
}
/**
* Main class
*/
public class sharedIntegerExample {
Integer class is not thread safe so two threads updated sharedInteger out of order.
So at end of program sharedInteger’s value was 3, whereas it should have been 4 because sharedInteger was initialized to 0 and was
incremented 4 times.
Executor and ExecutorService framework in java - Detailed explanation with full program
Executor and ExecutorService are used for following purposes in java >
creating thread,
starting threads,
managing whole life cycle of Threads.
Executor creates pool of threads and manages life cycle of all threads in it in java.
void shutdown()
Initiates shutdown of executor, previously submitted tasks are executed, but no new tasks will be accepted in java.
boolean isTerminated()
Method returns true if all tasks have completed following shut down in java.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable implements Runnable {
int taskNumber;
MyRunnable(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " executing task no " + taskNumber);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.1) Let’s discuss output in detail, to get better understanding of Executor and ExecutorService usage in program in java >
Note : I have mentioned output in green text.
2 threads in executor will be used for executing 10 tasks. So, at a time only 2 tasks will be executed
2 created threads in executor will be used for executing 10 tasks. So, at a time only 2 tasks will be executed.
If we analyze output at runtime we will notice that at a time only 2 tasks were executed.
We must shutdown executor after executing tasks.
So far in this thread concurrency tutorial we have learned what is Executor and ExecutorService framework in java with program and
examples. Now we will learn what are Future and Callable in java.
4) java.util.concurrent.Future<V> in java
Future interface provides methods in java >
for returning result of computation, wait until computation is not completed and
for cancelling the computation in between in java.
cancel method
method cancels the task.
5) java.util.concurrent.Callable<V> in java
Callable interface provides method for computing a result and returning that computed result or throws an exception if unable to do so
Any class implementing Callable interface must override call() method.
Future<Double> futureDouble=executor.submit(new
SquareDoubleCallable(2.2));
This Future object can check the status of a Callable call’s method and wait until Callable’s call() method is not completed.
6) Example/Program to demonstrate usage of java.util.concurrent.Callable and java.util.concurrent.Future in thread concurrency in java >
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class SumIntegerCallable implements Callable<Integer> {
Integer n;
SumIntegerCallable(Integer n) {
this.n = n;
}
@Override
public Integer call() throws Exception {
Integer sum = 0;
for (int i = 0; i <= n; i++) {
sum += i;
}
return sum;
}
}
class SquareDoubleCallable implements Callable<Double> {
Double n;
SquareDoubleCallable(Double n) {
this.n = n;
}
@Override
public Double call() throws Exception {
return n*n;
}
}
public class CallableFutureExample {
private static final int NTHREDS = 10;
public static void main(String[] args) throws InterruptedException, ExecutionException
{
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
Future<Integer> futureInteger=executor.submit(new SumIntegerCallable(4));
Future<Double> futureDouble=executor.submit(new SquareDoubleCallable(2.2));
executor.shutdown();
}
}
/*OUTPUT
SumIntegerCallable has returned > 10
SquareDoubleCallable has returned > 4.840000000000001
*/
In the above program - we submit a Callable object to an Executor and returned object was of Future type.
8) Using <T> Future<T> submit(Runnable task, T result) and Future<?> submit(Runnable task) in program in java >
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable's run()");
}
}
public class SubmitRunnableExample {
private static final int NTHREDS = 10;
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
Future<Integer> futureInteger=executor.submit(new MyRunnable(), 1);
System.out.println("futureInteger.get() > "+futureInteger.get());
when executor.submit(new MyRunnable()) was called, it internally called call() method and on successful completion of MyRunnable’s
run() method, futureInteger.get() returned null.
9) Differences between execute() and submit() method of executor framework in thread concurrency in java >
execute() method is defined in Executor submit() method is defined in ExecutorService interface in java.
interface in java.
It can be used for executing runnable It can be used for executing runnable task or callable task, submitted callable returns future
task. and Future's get method will return the task's result.
1.4) In short about CountDownLatch’s await() and countDown() method in java >
The await() methods block the current threads until the count reaches 0 due to invocations of the countDown() method by some other
thread, after which blocked threads are released.
CountDownLatch countDownLatch;
MyRunnable(CountDownLatch countDownLatch){
this.countDownLatch=countDownLatch;
}
for(int i=2;i>=0;i--){
countDownLatch.countDown();
System.out.println(Thread.currentThread().getName()+
" has reduced latch count to : "+ i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
2.1) Let’s discuss output in detail, to get better understanding of CountDownLatch usage in program in java >
Note : I have mentioned output in green text.
2.2) Occasionally, because of threads unpredictable behaviour output may be bit awkward in java >
/*OUTPUT
CountDownLatch has been created with count=3
Thread-1 has reduced latch count to : 2
Thread-1 has reduced latch count to : 1
count has reached zero, main thread has ended
Thread-1 has reduced latch count to : 0
*/
This may happen because as soon as count reaches 0 waiting threads are released. Here, as soon as Thread-1 called countDown() method
third time main thread was released and its sysout statement was executed before Thread-1’s sysout statement.
}
}
MyRunnable(CyclicBarrier cyclicBarrier){
this.cyclicBarrier=cyclicBarrier;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" is waiting for all other threads to reach common barrier point");
try {
Thread.sleep(1000);
/*
* when all 3 parties will call await() method (i.e. common barrier point)
* CyclicBarrrierEvent will be triggered and all waiting threads will be released.
*/
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
/*OUTPUT
CountDownLatch has been created with parties=3, when all 3 parties will reach common barrier point CyclicBarrrierEvent will be
triggered
Thread-1 is waiting for all other threads to reach common barrier point
Thread-2 is waiting for all other threads to reach common barrier point
Thread-3 is waiting for all other threads to reach common barrier point
As all threads have reached common barrier point , CyclicBarrrierEvent has been triggered
As all threads have reached common barrier point Thread-1 has been released
As all threads have reached common barrier point Thread-3 has been released
As all threads have reached common barrier point Thread-2 has been released
*/
2.1) Let’s discuss output in detail, to get better understanding of CyclicBarrier usage in program in java >
CountDownLatch has been created with parties=3, when all 3 parties will reach common
barrier point CyclicBarrrierEvent will be triggered
CountDownLatch has been created with parties=3, when Thread-1, Thread-2 and Thread-3 will call await() method, CyclicBarrrierEvent
will be triggered
Thread-1 is waiting for all other threads to reach common barrier point
Thread-1 has called await(), it is waiting for Thread-2 and Thread-3 to call await() method
Thread-2 is waiting for all other threads to reach common barrier point
Thread-1 and Thread-2 has called await(), and they are waiting for Thread-3 to call await() method
Thread-3 is waiting for all other threads to reach common barrier point
Thread-1, Thread-2, and Thread-3 has called await().
As all threads have reached common barrier point , CyclicBarrrierEvent has been triggered
As Thread-1, Thread-2, and Thread-3 has called await(). So, CyclicBarrrierEvent is triggered i.e. run() method of CyclicBarrrierEvent is
called
As all threads have reached common barrier point Thread-1 has been released
As all threads have reached common barrier point Thread-3 has been released
As all threads have reached common barrier point Thread-2 has been released
As Thread-1, Thread-2, and Thread-3 has called await(), all waiting threads are released and completes there execution.
When we execute 3 more threads in above program CyclicBarrrierEvent will be triggered again.
Output will be -
/*OUTPUT
CountDownLatch has been created with parties=3, when all 3 parties will reach common barrier point CyclicBarrrierEvent will be
triggered
Thread-1 is waiting for all other threads to reach common barrier point
Thread-2 is waiting for all other threads to reach common barrier point
Thread-3 is waiting for all other threads to reach common barrier point
As all threads have reached common barrier point , CyclicBarrrierEvent has been triggered
As all threads have reached common barrier point Thread-3 has been released
As all threads have reached common barrier point Thread-2 has been released
As all threads have reached common barrier point Thread-1 has been released
Thread-4 is waiting for all other threads to reach common barrier point
Thread-5 is waiting for all other threads to reach common barrier point
Thread-6 is waiting for all other threads to reach common barrier point
As all threads have reached common barrier point , CyclicBarrrierEvent has been triggered
As all threads have reached common barrier point Thread-6 has been released
As all threads have reached common barrier point Thread-4 has been released
As all threads have reached common barrier point Thread-5 has been released
*/
Now, when all threads have reached common barrier point (i.e. all friends have reached place A) >
All waiting threads are released (All friends can play game), and
Event can be triggered (they will start playing game).
1. First let’s discuss Similarity between CyclicBarrier and CountDownLatch in Java. CyclicBarrier and CountDownLatch are similar
because they wait for specified number of thread to reach certain point and make count/parties equal to 0. But ,
for completing wait in CountDownLatch specified number of threads must call countDown() method in Java.
for completing wait in CyclicBarrier specified number of threads must call await() method in Java.
3. This is very important difference between CyclicBarrier and CountDownLatch in java. CyclicBarrier can be awaited
repeatedly, but CountDownLatch can’t be awaited repeatedly. i.e. once count has become 0 cyclicBarrier can be used again but
CountDownLatch cannot be used again in Java.
4. Another important difference between CyclicBarrier and CountDownLatch in java. CyclicBarrier can be used to trigger event,
but CountDownLatch can’t be used to launch event. i.e. once count has become 0 cyclicBarrier can trigger event in Java but
CountDownLatch can’t.
So, in this thread concurrency tutorial we read what are Similarity and important Difference between CyclicBarrier and
CountDownLatch in Java.
Phaser(int parties)
Creates a new phaser with the parties number of registered unarrived parties.
Phaser is created without parent.
Initially phase number is 0.
/*
*Creates a new phaser (parentPhaser) with no registered unArrived parties
*/
Phaser parentPhaser = new Phaser();
/*
* Creates a new phaser (childPhaser ) with the given parent &
* no registered unArrived parties.
*/
Phaser childPhaser = new Phaser(parentPhaser,0);
Phaser(Phaser parent)
Internally it calls phaser(parent,0).
If invocation of onAdvance() method is in progress than before returning this method may await its completion.
If this phaser has a parent, and there were no registered parties with this phaser, this child phaser is also registered with its parent.
int arriveAndDeregister()
Current thread (Party) Arrives and deRegisters from phaser. DeRegistration reduces the number of parties that may be required in future to
move to next phase.
int arrive()
Method is called to signal that party (current thread) has completed a phase. It returns >
o the arrival phase number.
o If phaser has terminated then value is negative.
Does arrive() cause current thread to wait for other registered threads to complete current phase?
No, arrive() method does not cause current thread to wait for other registered threads to complete current phase. That means
current thread can immediately start next phase without waiting for any other registered thread to complete current phase.
int arriveAndAwaitAdvance()
Method is called to signal that party (current thread) has completed a phase.
It returns >
o the arrival phase number.
o If phaser has terminated then value is negative.
Does arriveAndAwaitAdvance() method causes current thread to wait for other registered threads to complete current phase?
Yes, arriveAndAwaitAdvance() method causes current thread to wait for other registered threads to complete current phase.
That means current thread can proceed to next phase only when all other threads have completed current phase (i.e. by calling
arriveAndAwaitAdvance() method).
int getPhase()
getPhase() method can be used for monitoring purposes. Method returns the current phase number.
For first phase it returns 0, for second phase it returns 1 and so on.
boolean isTerminated()
isTerminated() method returns true if phaser has been terminated.
We can override the onAdvance( ) method to control number of phases which we want to execute.
phase is the current phase number when we enter onAdvance() method i.e. before advancing to next phase.
registeredParties is the current number of registered parties
Everytime before advancing to next phase overriden onAdvance() method is called and returns either true or false.
If method returns true than phaser is terminated ,or
If method returns false than phaser continues and can advance to next phase.
Maximum number of parties that could be registered with phaser at a time is 65535, if we try to register more parties
IllegalStateException will be thrown in java.
//Create 3 threads
Thread thread1=new Thread(new MyRunnable(phaser,"first"),"Thread-1");
Thread thread2=new Thread(new MyRunnable(phaser,"second"),"Thread-2");
Thread thread3=new Thread(new MyRunnable(phaser,"third"),"Thread-3");
System.out.println("\n--------Phaser has started---------------");
//Start 3 threads
thread1.start();
thread2.start();
thread3.start();
//get current phase
int currentPhase=phaser.getPhase();
/*arriveAndAwaitAdvance() will cause thread to wait until current phase
* has been completed i.e. until all registered threads
* call arriveAndAwaitAdvance()
*/
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been
COMPLETED----------");
//------NEXT PHASE BEGINS------
currentPhase=phaser.getPhase();
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been
COMPLETED----------");
}
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister();
}
}
/*OUTPUT
new phaser with 1 registered unArrived parties created and initial phase number is 0
first - New unarrived party has been registered with phaser
second - New unarrived party has been registered with phaser
third - New unarrived party has been registered with phaser
--------Phaser has started---------------
Thread-1 - party has arrived and is working in Phase-0
Thread-2 - party has arrived and is working in Phase-0
Thread-3 - party has arrived and is working in Phase-0
------Phase-0 has been COMPLETED----------
Thread-3 - party has arrived and is working in Phase-1
Thread-2 - party has arrived and is working in Phase-1
Thread-1 - party has arrived and is working in Phase-1
------Phase-1 has been COMPLETED----------
Phaser has been terminated
*/
3.1) Let’s discuss output in detail, to get better understanding of Phaser usage in program in java >
Note : I have mentioned output in green text.
new phaser with 1 registered unArrived parties created and initial phase number is 0
Phaser phaser=new Phaser(1), Creates a new phaser with 1 registered unArrived parties and initial phase number is 0.
main thread has called arriveAndAwaitAdvance() and waiting for another 3 registered parties (Thread-1, Thread-2 and Thread-3) to call
arriveAndAwaitAdvance().
After working in phase-1 all the registered threads calls arriveAndAwaitAdvance() and than calls arriveAndDeregister(), now only main
thread is registered with phaser.
Main thread has called arriveAndAwaitAdvance() and then called arriveAndDeregister(), now there is no thread registered with phaser.
package PhaserParent;
import java.util.concurrent.Phaser;
public class PhaserParentChildTest {
public static void main(String[] args) {
/*
* Creates a new phaser with no registered unArrived parties.
*/
Phaser parentPhaser = new Phaser();
/*
* Creates a new phaser with the given parent &
* no registered unArrived parties.
*/
Phaser childPhaser = new Phaser(parentPhaser,0);
childPhaser.register();
System.out.println("parentPhaser isTerminated :
"+parentPhaser.isTerminated());
System.out.println("childPhaser isTerminated : "+childPhaser.isTerminated());
childPhaser.arriveAndDeregister();
System.out.println("\n--childPhaser has called arriveAndDeregister()-- \n");
System.out.println("parentPhaser isTerminated :
"+parentPhaser.isTerminated());
System.out.println("childPhaser isTerminated : "+childPhaser.isTerminated());
}
}
/* OUTPUT
parentPhaser isTerminated : false
childPhaser isTerminated : false
--childPhaser has called arriveAndDeregister()--
parentPhaser isTerminated : true
childPhaser isTerminated : true
*/
We created a parentPhaser with no registered unArrived parties. Than we created a childPhaser with the given parentPhaser & no registered
unArrived parties.
Then registered childPhaser . Then parentPhaser didn’t terminated until childPhaser was not terminated.
5) Example/ Program to demonstrate usage of how we can override Phaser’s onAdvance method to control number of phase we want to
execute in java>
Let me brief you about boolean onAdvance(int phase, int registeredParties) method.
phase is the current phase number when we enter onAdvance() method i.e. before advancing to next phase.
registeredParties is the current number of registered parties in java.
We can override the onAdvance( ) method to control number of phases which we want to execute in java.
Every Time before advancing to next phase overridden onAdvance() method is called and returns either true or false in java.
If method returns true then phaser is terminated ,or
If method returns false then phaser continues and can advance to next phase.
package PhaserOnAdvance;
import java.util.concurrent.Phaser;
/*
* class extending Phaser
*/
public class PhaserOnAdvanceTest extends Phaser{
/*
* Every time before advancing to next phase overridden
* onAdvance() method is called and returns either true or false.
*/
@Override
protected boolean onAdvance(int phase, int registeredParties) {
//Create 3 threads
Thread thread1=new Thread(new MyRunnable(phaser,"first"),"Thread-1");
Thread thread2=new Thread(new MyRunnable(phaser,"second"),"Thread-2");
Thread thread3=new Thread(new MyRunnable(phaser,"third"),"Thread-3");
System.out.println("\n--------Phaser has started---------------");
//Start 3 threads
thread1.start();
thread2.start();
thread3.start();
while(!phaser.isTerminated()){
//get current phase
int currentPhase=phaser.getPhase();
/*arriveAndAwaitAdvance() will cause thread to wait until current phase
* has been completed i.e. until all registered threads
* call arriveAndAwaitAdvance()
*/
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been COMPLETED----------");
}
}
}
class MyRunnable implements Runnable{
Phaser phaser;
@Override
public void run() {
while(!phaser.isTerminated()){
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
}
/*OUTPUT
new phaser with 1 registered unArrived parties created and initial phase number is 0
first - New unarrived party has been registered with phaser
second - New unarrived party has been registered with phaser
third - New unarrived party has been registered with phaser
--------Phaser has started---------------
Thread-1 - party has arrived and is working in Phase-0
Thread-2 - party has arrived and is working in Phase-0
Thread-3 - party has arrived and is working in Phase-0
onAdvance() method, current phase=0
onAdvance() method, returning false, hence phaser will continue
------Phase-0 has been COMPLETED----------
Thread-2 - party has arrived and is working in Phase-1
Thread-1 - party has arrived and is working in Phase-1
Thread-3 - party has arrived and is working in Phase-1
onAdvance() method, current phase=1
onAdvance() method, returning true, hence phaser will terminate
------Phase-1 has been COMPLETED----------
*/
5.1) Let’s discuss output in detail, to get better understanding of how we can override Phaser’s onAdvance method to control number of
phase we want to execute in java >
Note : I have mentioned output in green text.
new phaser with 1 registered unArrived parties created and initial phase number is 0
public PhaserOnAdvanceTest(int parties) {
super(parties);
}
Creates a new phaser with 1 registered unArrived parties and initial phase number is 0.
SUMMARY>
In this thread concurrency tutorial we learned what is java.util.concurrent.Phaser in java with program and examples. We also wrote
programs to demonstrate usage of Phaser in thread concurrency in java.
void lock()
Acquires the lock if it is not held by another thread. And sets lock hold count to 1.
If current thread already holds lock then lock hold count is increased by 1.
If the lock is held by another thread then the current thread waits for another thread to release lock.
void unlock()
If the current thread is holding the lock then the lock hold count is decremented by 1. If the lock hold count has reached 0, then the lock is
released.
If lock hold count is still greater than 0 then lock is not released.
If the current thread is not holding the lock then IllegalMonitorStateException is thrown.
boolean tryLock()
Acquires the lock if it is not held by another thread and returns true. And sets lock hold count to 1.
If current thread already holds lock then method returns true. And increments lock hold count by 1.
If lock is held by another thread then method return false.
If the lock is acquired then method returns true. And sets lock hold count to 1.
If specified timeout elapses then method return false.
Condition newCondition()
Method returns a Condition instance to be used with this Lock instance.
Condition instance are similar to using Wait(), notify() and notifyAll() methods.
IllegalMonitorStateException is thrown if this lock is not held when any of the Condition waiting or signalling methods are
called.
Lock is released when the condition waiting methods are called and before they return, the lock is reacquired and the lock
hold count restored to what it was when the method was called.
If a thread is interrupted while waiting then InterruptedException will be thrown and following things will happen -
o the wait will be over, and
o thread's interrupted status will be cleared.
Waiting threads are signalled in FIFO (first in first out order) order.
When lock is fair, first lock is obtained by longest-waiting thread.
If lock is not fair, any waiting thread could get lock, at discretion of implementation.
Program/ Example to demonstrate usage of newCondition() method - solving Producer consumer problem >
ReentrantLock(boolean fair)
Creates an instance of ReentrantLock.
When fair is set true, first lock is obtained by longest-waiting thread.
If fair is set false, any waiting thread could get lock, at discretion of implementation.
int getQueueLength()
Method returns number of threads that may be waiting to acquire this lock.
Method is used just for monitoring purposes and not for any kind of synchronization purposes.
boolean isHeldByCurrentThread()
Method returns true if lock is held by current thread. Its similar to Thread.holdsLock() method.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest {
public static void main(String[] args) {
Lock lock=new ReentrantLock();
MyRunnable myRunnable=new MyRunnable(lock);
new Thread(myRunnable,"Thread-1").start();
new Thread(myRunnable,"Thread-2").start();
}
}
System.out.println(Thread.currentThread().getName()
+" is Waiting to acquire lock");
lock.lock();
System.out.println(Thread.currentThread().getName()
+" has acquired lock.");
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()
+" is sleeping.");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+" has released lock.");
lock.unlock();
}
}
/*OUTPUT
Thread-1 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock
Thread-1 has acquired lock.
Thread-1 is sleeping.
Thread-1 has released lock.
Thread-2 has acquired lock.
Thread-2 is sleeping.
Thread-2 has released lock.
*/
6.1) Let’s discuss output in detail, to get better understanding of ReentrantLock usage in program in java >
Note : I have mentioned output in green text.
Thread-1 is sleeping.
Thread-1 has released lock.
Thread-1 has released lock by calling unlock() method. (Now lock hold count=0)
Thread-2 is sleeping.
Thread-2 has released lock.
Thread-2 has released lock by calling unlock() method. (Now lock hold count=0)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTryLockTest {
public static void main(String[] args) {
Lock lock=new ReentrantLock();
MyRunnable myRunnable=new MyRunnable(lock);
new Thread(myRunnable,"Thread-1").start();
new Thread(myRunnable,"Thread-2").start();
}
}
Lock lock;
public MyRunnable(Lock lock) {
this.lock=lock;
}
System.out.println(Thread.currentThread().getName()
+" is Waiting to acquire lock");
if(lock.tryLock()){
System.out.println(Thread.currentThread().getName()
+" has acquired lock.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
System.out.println(Thread.currentThread().getName()
+" didn't got lock.");
}
}
}
/*OUTPUT
Thread-1 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock
Thread-1 has acquired lock.
Thread-2 didn't got lock.
*/
7.1) Let’s discuss output in detail, to get better understanding of ReentrantLock’s tryLock() method usage in program in java >
Note : I have mentioned output in green text.
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockGetQueuedThreadTest {
public static void main(String[] args) {
ReentrantLock lock=new ReentrantLock();
MyRunnable myRunnable=new MyRunnable(lock);
new Thread(myRunnable,"Thread-1").start();
new Thread(myRunnable,"Thread-2").start();
new Thread(myRunnable,"Thread-3").start();
}
}
ReentrantLock lock;
public MyRunnable(ReentrantLock lock) {
this.lock=lock;
}
System.out.println(Thread.currentThread().getName()
+" is Waiting to acquire lock");
lock.lock();
System.out.println(Thread.currentThread().getName()
+" has acquired lock.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(">>>>--- getQueueLength = "+lock.getQueueLength()+"---<<<<");
System.out.println(Thread.currentThread().getName()
+" has released lock.");
8.1) Let’s discuss output in detail, to get better understanding of ReentrantLock’s getQueueLength() method usage in program in java >
Thread-1 is Waiting to acquire lock
Thread-3 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock
Thread-1 has acquired lock.
>>>>--- getQueueLength = 2---<<<<
At this moment Thread-2 and Thread-3 were waiting for lock.
Thread-1 has released lock.
Thread-3 has acquired lock.
>>>>--- getQueueLength = 1---<<<<
At this moment Thread-2 was waiting for lock.
Thread-3 has released lock.
Thread-2 has acquired lock.
>>>>--- getQueueLength = 0---<<<<
At this moment no thread was waiting for lock.
Thread-2 has released lock.
Reentrantlocks can be used to solve Train-passenger problem when 2 passengers try to book train ticket, when only 1 ticket is
available.
Program to show that with Reentrantlocks no problems will happen when 2 passengers try to book train ticket, when only 1 ticket was
available >
import java.util.concurrent.locks.Lock;
public class ReentrantLockTest {
public static void main(String[] args) {
Lock lock=new ReentrantLock();
MyRunnable myRunnable=new MyRunnable(lock);
new Thread(myRunnable,"Passenger1 Thread").start();
new Thread(myRunnable,"Passenger2 Thread").start();
}
}
int ticketsAvailable=1;
Lock lock;
public MyRunnable(Lock lock) {
this.lock=lock;
}
lock.lock();
if(ticketsAvailable>0){
System.out.println("Booking ticket for : "+
Thread.currentThread().getName());
ticketsAvailable--;
System.out.println("Ticket BOOKED for : "+
Thread.currentThread().getName());
System.out.println("currently ticketsAvailable = "+ticketsAvailable);
}
else{
System.out.println("Ticket NOT BOOKED for : "+
Thread.currentThread().getName());
}
10) What will happen if thread that holds lock again calls lock() method in java?
Initially lock hold count = 0. When thread calls lock() method lock hold count is set to one (Now, lock hold count =1). If same thread
again calls lock() method lock hold count is incremented by one (Now, lock hold count =2).
Now some other thread will be able to acquire lock only when lock hold count is 0. Thread will have to wait until lock hold count becomes
0.
When same thread calls unlock() method lock hold count is decremented by one (Now, lock hold count =1) and thread won’t release
lock. If same thread again calls unlock() method lock hold count is decremented by one (Now, lock hold count =0), thread will release
lock and some other thread can acquire lock.
10.1) Program/ Example to show what will happen if thread that holds lock again calls lock() method in java >
import java.util.concurrent.locks.Lock;
public class ReentrantLockTest {
public static void main(String[] args) {
Lock lock=new ReentrantLock();
MyRunnable myRunnable=new MyRunnable(lock);
new Thread(myRunnable,"Thread-1").start();
new Thread(myRunnable,"Thread-2").start();
}
}
Lock lock;
public MyRunnable(Lock lock) {
this.lock=lock;
}
System.out.println(Thread.currentThread().getName()
+" is Waiting to acquire lock");
lock.lock();
System.out.println();
System.out.println(Thread.currentThread().getName()
+" has called lock(), lockHoldCount=1 ");
lock.lock();
System.out.println(Thread.currentThread().getName()
+" has called lock(), lockHoldCount=2 ");
System.out.println(Thread.currentThread().getName()
+" is about to call unlock(), lockHoldCount will become 1 ");
lock.unlock();
System.out.println(Thread.currentThread().getName()
+" is about to call unlock(), lockHoldCount will become 0 ");
lock.unlock();
}
}
/*OUTPUT
Thread-2 is Waiting to acquire lock
Thread-1 is Waiting to acquire lock
Thread-2 has called lock(), lockHoldCount=1
Thread-2 has called lock(), lockHoldCount=2
Thread-2 is about to call unlock(), lockHoldCount will become 1
Thread-2 is about to call unlock(), lockHoldCount will become 0
Thread-1 has called lock(), lockHoldCount=1
Thread-1 has called lock(), lockHoldCount=2
Thread-1 is about to call unlock(), lockHoldCount will become 1
Thread-1 is about to call unlock(), lockHoldCount will become 0
*/
Synchronized ReentrantLock
Does not provide any fair locks in java. provides fair locks, when lock is fair - first lock is obtained by longest-waiting
thread in java.
ReentrantLock(boolean fair)
Creates an instance of ReentrantLock.
When fair is set true, first lock is obtained by longest-waiting thread.
If fair is set false, any waiting thread could get lock, at discretion of
implementation.
Does not provide tryLock() method or its Provide tryLock() method. If lock is held by another thread then method
functionality. Thread always waits for lock in return false in java.
java.
boolean tryLock()
Acquires the lock if it is not held by another thread and returns true. And sets lock
hold count to 1.
If current thread already holds lock then method returns true. And increments lock
hold count by 1.
If lock is held by another thread then method return false.
Does not provide any method to return provide int getQueueLength() method to return number of threads that may be
number of threads that may be waiting to waiting to acquire this lock in java.
acquire this lock in java.
holdsLock() method is used to find out whether isHeldByCurrentThread() method is used to find out whether lock is held by
lock is held by current thread or not. If current current thread or not. If current thread holds lock method returns true in java.
thread holds lock method returns true.
Thread can hold lock on object monitor only if current thread already holds lock then lock hold count is increased by 1 when
once. lock() method is called.
Lock is released when the condition waiting methods are called and
before they return, the lock is reacquired and the lock hold count restored to what it
was when the method was called in java.
Waiting threads are signalled in FIFO (first in first out order) order.
When lock is fair, first lock is obtained by longest-waiting thread.
If lock is not fair, any waiting thread could get lock, at discretion of
implementation in java.
So, in this thread concurrency tutorial we read what are differences between synchronized and ReEntrantLocks in java
Now, let's figure out difference between SERIALIZABLE and EXTERNALIZABLE >
SERIALIZABLE EXTERNALIZABLE
Methods It is a marker interface it doesn’t have any It’s not a marker interface.
method. It has method’s called writeExternal() and
readExternal()
Default Serialization YES, Serializable provides its own default NO, we need to override writeExternal() and
process serialization process, we just need to implement readExternal() for serialization process to happen.
Serializable interface.
Customize We can customize default serialization process Serialization process is completely customized
serialization process by defining following methods in our class We need to override Externalizable interface’s
>readObject() and writeObject() writeExternal() and readExternal() methods.
Note: We are not overriding these methods, we
are defining them in our class.
Control over It provides less control over Serialization as it’s Externalizable provides you great control over
Serialization not mandatory to define readObject() and serialization process as it is important to override
writeObject() methods. writeExternal() and readExternal() methods.
Constructor call Constructor is not called during deSerialization. Constructor is called during deSerialization.
during
deSerialization
Significance of using Static and Transient member variables - Static and Transient are not serialized in java
Why static member variables are not part of java serialization process ?
Serialization is applicable on objects or primitive data types only, but static members are class level variables, therefore, different object’s
of same class have same value for static member.
So, serializing static member will consume unnecessary space and time.
Also, if modification is made in static member by any of the object, it won’t be in sync with other serialized object’s value.
What is significance of transient variables?
Serialization is not applicable on transient variables (it helps in saving time and space during Serialization process), we must mark all
rarely used variables as transient. We can initialize transient variables during deSerialization by customizing deSerialization process.
How can you avoid certain member variables of class from getting Serialized?
Mark member variables as static or transient, and those member variables will no more be a part of Serialization.
What is serialVersionUID? Impact of not defining serialVersionUID in class and avoiding InvalidClassException in
java
The serialization at runtime associates with each serializable class a version number, called a serialVersionUID, which is used during
deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect
to serialization.
We can use eclipse to generate serialVersionUID for our class (as done in below snapshot)
How to avoid warning ‘The serializable class Employee does not declare a static final serialVersionUID field of type long’ ?
Again answer is we can use eclipse to generate serialVersionUID for our class (as mentioned in above screenshot, click on warning button
on left in line 10).
If you have serialized a class & then added few fields in it and then deserialize already serialized version of class, how can you ensure that
you don’t end up throwing InvalidClassException?
>Simply we need to define serialVersionUID in class.
When we Deserialize class ( class which has been modified after Serialization and also class doesn’t declare SerialVersionUID)
InvalidClassException is thrown.
When we Deserialize class ( class which has been modified after Serialization and also class declare SerialVersionUID) its gets
DeSerialized successfully.
First we will serialize a class (class which implements Serialization, but we haven’t declared SerialVersionUID)
package serDeser4AddSUID;
Then modify class by adding one field in class, but ensure that you don’t run the Serialization process again.
Modify the Serialized class (but don’t serialize the class again)>
class Employee implements Serializable {
Now, we have added addedField in class which was already Serialized, let’s see in absence of SerialVersionUID whether we will be able to
DeSerialize our class or not.
package serDeser4AddSUID;
public class DeSerializeEmployee {
}
}
/*OUTPUT
DeSerialization process has started, displaying employee objects...
java.io.InvalidClassException: serDeser4AddSUID.Employee; local class incompatible: stream classdesc serialVersionUID =
4822384361417160410, local class serialVersionUID = 5590647880449995492
Object deSerialization completed.
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at serDeser4AddSUID.DeSerializeEmployee.main(DeSerializeEmployee.java:18)
*/
DeSerialization process has ended up throwing InvalidClassException.
Now, let’s see what will happen when we declare serialVersionUID in Serializable class.
package serDeser4AddSUID;
class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
Then modify class by adding one field in class, but ensure that you don’t run the Serialization process again.
Modify the Serialized class (but don’t serialize the class again)>
Now, we have added addedField in class which was already Serialized, let’s see in presence of SerialVersionUID whether we will be able
to DeSerialize our class or not.
Program 4 - to DeSerialize object - Object will be DeSerialized successfully (without InvalidClassException) >
package serDeser4AddSUID;
public class DeSerializeEmployee {
}
}
/*OUTPUT
DeSerialization process has started, displaying employee objects...
Employee [id=1, name=amy]
Employee [id=2, name=ankit]
Object deSerialization completed.
*/
DeSerialization process has ended up successfully.
InCompatible Changes :
InCompatible changes are those changes which affect deSerialization process if class was updated after being serialized (provided
serialVersionUID has been declared)
Deletion of fields. (http://stackoverflow.com/questions/16261383/delete-field-from-old-java-class-implementing-
serializable)
Changing a nonstatic field to static or non transient field to transient field. - it’s equal to deletion of fields.
Modifying the writeObject() / readObject() method - we must not modify these method, though adding or removing them
completely is compatible change.
If member of class does not implement Serializable interface - than NotSerializableException is thrown in java.
If any of the member does not implement Serializable than NotSerializableException is thrown.
package SerDeser10memberNotSer;
class MyClass {}
class Employee implements Serializable {
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*OUTPUT
Serialization process has started, serializing objects...
java.io.NotSerializableException: SerDeser10memberNotSer.MyClass
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at
SerDeser10memberNotSer.SerializeConstructorCheck.main(SerializeConstructorCheck.java:42)
*/
If we note output, myClass didn’t implemented Serializable interface that’s why Serialization process has thrown NotSerializableException.
How to avoid NotSerializableException?
We got to ensure that during Serialization all the members of class implements Serializable.
ArrayList, HashSet and HashMap implements Serializable interface, so if we will use them as member of class they will get Serialized and
DeSerialized as well.
Full Program/SourceCode to show list, set and maps are Serializable and DeSerializable objects>
package serDeser6ListSetMap;
class MyClass implements Serializable {
}
public class SerializeEmployee {
public static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
list.add(2);
list.add(3);
Set<Integer> set=new HashSet<Integer>();
set.add(4);
set.add(5);
Map<Integer, Integer> map=new HashMap<Integer,Integer>();
map.put(6, 34);
map.put(7, 35);
If we note output, we were successfully able to Serialize and DeSerialize list, set and map objects.
If Serializable has been implemented - constructor is not called during DeSerialization process.
But, if Externalizable has been implemented - constructor is called during DeSerialization process.
Full Program/SourceCode to show that If Serializable has been implemented - constructor is not called during DeSerialization process.
package SerDeser7SerConsCheck;
public Employee(){
System.out.println("No-arg constructor called");
}
Full Program/SourceCode to show that if Externalizable has been implemented - constructor is called during DeSerialization process.
>
package SerDeser7ExtConsCheck;
class Employee implements Externalizable {
public Employee(){
System.out.println("No-arg constructor called");
}
/*
* define how deSerialization process will read objects.
*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id=in.readInt();
}
}
public class ExternalizableConstructorCheck {
public static void main(String[] args) {
Employee object1 = new Employee(8);
try {
OutputStream fout = new FileOutputStream("ser.txt");
ObjectOutput oout = new ObjectOutputStream(fout);
System.out.println("Serialization process has started, serializing employee objects...");
oout.writeObject(object1);
fout.close();
oout.close();
System.out.println("Object Serialization completed.");
Is constructor of super class called during DeSerialization process of sub class in java
It is depends on whether our superclass has implemented Serializable or not.
If superclass has implemented Serializable - constructor is not called during DeSerialization process.
If superclass has not implemented Serializable - constructor is called during DeSerialization process.
Full Program/SourceCode to show that If superclass has implemented Serializable - constructor is not called during DeSerialization
process.
package SerDeser9SuperConsCheck;
class Super implements Serializable{
private static final long serialVersionUID = 1L;
public Super(){
System.out.println("No-arg constructor of Super class");
}
}
class Sub extends Super { //it automatically implements Serializable (because it's subclass implements
Serializable).
public Sub(){
System.out.println("No-arg constructor of sub class");
}
Full Program/SourceCode to show that If superclass has not implemented Serializable - constructor is called during DeSerialization
process.
>
package SerDeser9SuperConsCheck;
class Super {
public Super(){
System.out.println("No-arg constructor of Super class");
}
}
class Sub extends Super implements Serializable{ //it automatically implements Serializable (because it's subclass implements
Serializable).
public Sub(){
System.out.println("No-arg constructor of sub class");
}
Can subclass avoid Serialization if its superClass has implemented Serialization interface in java
If superClass has implemented Serializable that means subclass is also Serializable (as subclass always inherits all features from its
parent class), for avoiding Serialization in sub-class we can define writeObject() method and throw NotSerializableException() from
there as done below.
Full Program/SourceCode to show how subclass can avoid Serialization if its superClass has implemented Serialization interface>
package SerDeser11throwNotSerExc;
class Super implements Serializable{
private static final long serialVersionUID = 1L;
}
class Sub extends Super {
/*
* define how Serialization process will write objects.
*/
private void writeObject(ObjectOutputStream os) throws NotSerializableException
{
throw new NotSerializableException("This class cannot be Serialized");
}
}
public class SerializeDeserialize {
public static void main(String[] args) {
Sub object1 = new Sub(8);
try {
OutputStream fout = new FileOutputStream("ser.txt");
ObjectOutput oout = new ObjectOutputStream(fout);
System.out.println("Serialization process has started, serializing objects...");
oout.writeObject(object1);
fout.close();
oout.close();
System.out.println("Object Serialization completed.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*OUTPUT
Serialization process has started, serializing objects...
java.io.NotSerializableException: This class cannot be Serialized
*/
If we note output, subclass was Serializable (as subclass always inherits all features from its parent class), for avoiding Serialization in
sub-class we defined writeObject() method and throwed NotSerializableException() from there.
Full Program/SourceCode to show that primitive types are also part of Serialization>
package serDeser5PrimitiveTypes;
class Employee implements Serializable {
package collection.programs;
output:-
"C:\Program Files\Java\jdk1.8.0_151\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community
Edition 2020.2.2\lib\idea_rt.jar=64861:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.2.2\bin" -
Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_151\jre\lib\charsets.jar;C:\Program
collection.programs.ArrayList_SynchronizationTest
main running
Thread-0 running
Thread-1 running
Exception in thread "Thread-1" java.util.ConcurrentModificationException
Note :
RunTimeException) will be thrown. Because, internally TreeMap calls compare method for comparing keys , while
comparing keys casting to java.lang.Comparable will fail at runtime.*/
/*
*TreeMap is sorted by natural order of keys, but we will implement Comparator interface to change the behaviour to sort
TreeMap in descending order of keys.
Comparator interface has been used in form of anonymous inner class in java.
*/
I worked on the List Interface, Set Interface, and Map Interface. I used the Implementation of
List as ArrayList and LinkedList. As part of Set Implementation, I have worked on HashSet,
LinkedHashSet and TreeSet. As part of Map Implementation, I worked on HashMap,
LinkedHashMap and TreeMap.
Also, there is few more implementation class like CopyOnWriteArrayList,
CopyOnWriteArraySet and ConcurrentHashMap. Which introduced in
java.util.concurrent.* package.
It’s always recommended to use the Type Generic that’s why my List will only allow to store
the String Object. So, there will be no Type Cast issue we will face in future if you maintain
the Generic.
6. Declaring a List field with the final keyword ?
Here I declared the list as a final now interviewer will try to understand after declaring List as
a final whether you are able to add the object to this list or not. Even though we declared it as
a final we can modified it there is no immutability. Still, we can modify but we can’t re-
assign this list. With the same reference we can’t create another object. But final doesn’t
mean we can’t modify it.
If you don’t want to modify the List, then you can use
Collections.unmodifiableList(list)
7. How Can I write Custom ArrayList where I don’t want to allow duplicate ?
We know array list will allow duplicate. But I want to create my own ArrayList where I stop allowing the
duplicates.
I have created a class called CustomArrayList we just need to extend it from ArrayList. Then we will use its
own method from the ArrayList method, and we will override the method and we will provide our own logic.
So, I will just override the add() method from the array list.
Now let’s add couple of duplicate values in our customize array list.
So, we can see it doesn’t allow duplicate objects in our list.
So, this is how you can create your own custom array list by extending it from ArrayList or any LinkedList and
you can provide your own implementation to stop allowing duplicates.
If you observed the object of add method of HashSet. It will add as a key of a Map. Which
means Set method internally uses a Map. So, add method of HashSet internally uses the map
object to store the value. where we considered the passed argument as a key and Value as a
PRESENT which is nothing but a dummy object value.
So PRESENT is a dummy object. It means Set implementation internally uses a Map to store
object as a key, as we know map key will not allow a duplicate element.
9. Does Set implementation always follow the same rule it does not allow the duplicate
elements ?
No, there is some certain rule if that is not followed by any of the HashSet or any of the Set
implementation or Map implementation then it will allow duplicate object.
Now let me explain that scenario. Let’s assume I have a Student class.
As per rule this Set should not allow duplicate object, right? Bcz s1 and s2 are the same
object it should print only one of them and s3. But we can see all the 3 objects.
Which means Set is not following the rule it allowing duplicates. So, there is a
difference.
If you are using Set with a primitive data type, then its fine no need to override equals() and
hashcode() methods. But if you are using any Custom object or Wrapper Class then you
must need to override equals() and hashCode() methods.
So, let’s override equals() and hashCode() methods.
Now we are getting 2 objects. Which means even though you are using HashSet or HashMap
that’s not guarantee it will not allow duplicate but yes if your custom object is overriding
equals() and hashCode() methods. If they follow the contract of equals() and hashCode()
then always you will get the unique object. There will be no duplicate.
So, This is one of the Interview Question To explain the contract between equals(0 and
hashCode() methods…
If I will use Comparable, then it will directly affect my actual class which is Employee.
Now in future I got a requirement just change the sorting mechanism based on some other
field now again I need to change this code so in case of comparable its not dynamic its
always like hard coded.
This will recommend if u want to do based on single sorting mechanism.
If I want to sort based on multiple parameters, we should go for Comparator.
//sort based on Id
11. I just want to sort based on Id if I found Id is same then I will go with the name
sorting ?
So, this comparator basically sort based on Id if it found both the id of its object is same then
it will sort based on the name.
But in case of ConcurrentHashMap We are not getting error here bcz it is not using your
cloned copy of Collection implementation. Since we are using Map here so there will be no
copy if u can observe we are getting all the 3 objects. But in case of CopyOnWriteArrayList
we are not getting all values bcz it returns cloned copy of collection bcz when modCount is
getter than expectedModCount it will create a cloned copy of collection instead of throwing
ConcurrentModificationException. But in case of map the implementation is different
there is no cloned copy concepts.
So, you can use ConcurrentHashMap whenever you want to access through parallel
threads or while iterating you want to modify something you can go for
ConcurrentHashMap.
14. What is the need of ConcurrentHashMap and How it is different from HashMap ?
So, let’s say you are iterating it now I iterate the first entry since it starts from 0.so its try iterating 100 and A. in
middle thread context switching happened so immediately it will go there and it will add another object. because
we don’t know which thread will execute first parent or child thread. That will be depends on your thread
scheduler. Then child thread will release the lock and main thread will add another entry and what
ConcurrentHashMap does.
It just applies lock on the Segment Level. Rather than applying lock on the entire underlying collection
object. So, HashMap is non synchronized but ConcurrentHashMap is synchronized.
HashMap apply lock on entire object where ConcurrentHashMap applies lock based on the segment. So that is
called segment locking or bucket locking in ConcurrentHashMap.
15. HashMap allows null key or value but ConcurrentHashMap doesn’t allow?
So, in case of key and value is null HashMap not giving any exception. Now if I will change it to the
ConcurrentHashMap I will get the NullPointerException.
Now if I will go to this implementation
Now when I use map.put(e1, “Dev”) . now how HashMap will identified where I need to keep this entry
between 0 to 15. So, what HashMap internally will do when we call put method. Inside put method there is a
method called hash(key) it will take argument as your key, so my key is nothing Employee 1 object so it will
pass to the hash function it will evaluate some hash value and then based on the modular operator it will identify
the index.
Let’s assume this first entry evaluate index 6 now simply this entry or this node will simply go and
store in bucket 6. My bucket 6 is nothing a linked list and it will store one node. Now I am trying to add 2 nd
object again it will come to the put method and again it will evaluate the hash and then again it evaluates the
index. It evaluates the index as 9. then it will simply go and store in my bucket 9. So, we can see again it store
key, value, hash and next reference null bcz no next node present in that current bucket.
Now let me add 3rd object e3 with some different string. Again, it come to the put method and it evaluate the
hash then it find the index coincidently let’s assume it find the same index which is 6. Now if we will go and
check there is already one element. Now if in a same bucket if you find multiple nodes then that concept is
called Hashing Collison.
So, in that Hashing Collison directly my map will not add this entry to the bucket number which is evaluated by
this index which is 6. So, what it will internally do since both having the same hash value, so it places on the
same bucket immediately map go and check the equals methods e1.equals(e3) to check content wise both are
different or same. If it finds different, then immediately it will store that entry to the same bucket which is
nothing but 6 and now the first entry node next value will not be null it will be the reference of second next node
and the second node next would be the null.
If in a same bucket there is a multiple node, then this condition is called Hashing Collison. So, to avoid the
hashing Collison map internally use == operator to check the reference if both are same reference or different
reference. If it found same reference it will just replace if it found different reference then immediately it will go
and check the content so, the content between the e1 and e3. e1 equal to e3 if it is true then again it will replace
if it found different then it will just add as a next node right to the first node.
Now we have one more element which is e4 let’s assume it found the index 7. Then that node directly goes to
the 7 bucket.
Now interviewer immediately ask you let’s say I pass the key as a null. In map I pass key as a null and a value
as a null then where it will place. Bcz we can’t evaluate the hash and index based on null. If the key is null then
the entry will be added into the 0 bucket.
This is the Internal Implementation of HashMap.
19. What is the enhancement done in HashMap java 8 ?
Initially in this HashMap each Bucket is used as a linked list but in certain threshold it will converted to the
Balance Tree mechanism. That will not be linked list. Let’s say there is a hashing Collison, in the same bucket
they found 5 nodes. Then immediately that linked list will convert to the balance tree and then it will maintain
the balanced between the nodes. Now sure much on Balanced tree internal architecture just go and found on
google.
Initially it will use LinkedList only but after some threshold it will converted to the balanced tree.
20. If key is null in HashMap then where that entry will store in map ?
If the key is null, then the entry will be added into the 0 bucket.
21. Map Enhancement in Java 8 ?
22. How TreeMap internally works?
if you use TreeMap any object will add as a key will preserved the default sorting order then how it is doing the
default sorting order. Let’s see internal implementation.
Now what happened already one entry exist key as a and value as a xyz now whenever you will try to add the
second entry or second object as a key what tree map internally do it will simply check “d”.compareTo(“a”). d
is nothing just a second key compared to the first key which is a. now this compareTo method will always
return integer. now “d”.compareTo(“a”) if it is greater than then it will just as to the right side and it will
return +positive one. If it is less than then it will add to the left side. How it will know that is less than or greater
than based on the return type either +ve or -ve.
So, it will just compare each object or each key if compareTo method return +1 then it will simply add in right
side if it will return -1 then it will simply add in left side. So, this is how it will work.
Let’s see one example …