Important points to remember or refresh before for core java interview


Foundations of OOP

• Encapsulation: Combining data and the functions operating on it as a single unit.
• Abstraction: Hiding lower-level details and exposing only the essential and relevant details tothe users.
• Inheritance: Creating hierarchical relationships between related classes.
• Polymorphism: Interpreting the same message (i.e., method call) with different meaningsdepending on the context.

Class Foundations

A “class” is a template (or blueprint) and an “object” is an instance of a class.
A constructor does not have a return type.
You cannot access the private methods of the base class in the derived class.
You can access the protected method either from a class in the same package (just like packageprivate or default) as well as from a derived class.
You can also access a method with a default access modifier if it is in the same package.
You can access public methods of a class from any other class.

Overloading

Method overloading: Creating methods with same name but different types and/or numbers of parameters.
You can have overloaded constructors. You can call a constructor of the same class in another constructor usingthe this keyword.
Overload resolution is the process by which the compiler looks to resolve a call when overloaded definitions of a method are available.

Inheritance

Inheritance is also called an “is-a” relationship.
Resolving a method call based on the dynamic type of the object is referred to as runtimepolymorphism.
In overriding, the name of the method, number of arguments, types of arguments, and returntype should match exactly.
In covariant return types, you can provide the derived class of the return type in the overriding method.
You use the super keyword to call base class methods.
Overloading is an example of static polymorphism (early binding) while overriding is anexample of dynamic polymorphism (late binding).
You don’t need to do an explicit cast for doing an upcast. An upcast will always succeed.
You need to do an explicit cast for doing a downcast. A downcast may fail. So you can use theinstanceof operator to see if a downcast is valid.

Java Packages

A package is a scoping construct to categorize your classes and to provide namespacemanagement.


Abstract Classes

An abstraction specifying functionality supported without disclosing finer level details.
You cannot create instances of an abstract class.
Abstract classes enable runtime polymorphism, and runtime polymorphism in turn enables loose coupling.

Using the “final” Keyword

A final class is a non-inheritable class (i.e., you cannot inherit from a final class).
A final method is a non-overridable method (i.e., subclasses cannot override a final method).
All methods of a final class are implicitly final (i.e., non-overridable).
A final variable can be assigned only once.

Using the “static” Keyword

There are two types of member variables: c lass variables and instance variables. All variablesthat require an instance (object) of the class to access them are known as instance variables.
All variables that are shared among all instances and are associated with a class rather than an object are referred to as class variables (declared using the static keyword).
All static members do not require an instance to call/access them. You can directly call/access them using the class name.
A static member can call/access only a static member.

Flavors of Nested Classes

Java supports four types of nested classes: static nested classes, inner classes, local inner classes, and anonymous inner classes.
Static nested classes may have static members, whereas the other flavors of nested classes can’t.
Static nested classes and inner classes can access members of an outer class (even private members). However, static nested classes can access only static members of outer class.
Local classes (both local inner classes and anonymous inner classes) can access all variables declared in the outer scope (whether a method, constructor, or a statement block).

Enums

Enums are a typesafe way to achieve restricted input from users.
You cannot use new with enums, even inside the enum definition.
Enum classes are by default final classes.
All enum classes are implicitly derived from java.lang.Enum.

Interfaces

An interface is a set of abstract methods that defines a protocol.
An interface cannot be instantiated; however, an interface can extend another interface.
All methods declared in an interface are implicitly considered to be abstract.
Abstract class and interface are quite similar concepts. However, you should be careful to use the appropriate construct based on the context.

Object Composition

Inheritance implies is-a, interface implies is-like-a, and composition implies has-a relationships.
Favor composition over inheritance whenever feasible.
Program to an interface, not to an implementation.

Design Patterns

Design patterns are reusable solutions of frequently recurring design problems.
The observer design pattern improves loose coupling between subject and observers.
The singleton design pattern ensures that only one instance of the class is created.
Making sure that an intended singleton implementation is indeed singleton is a non-trivial task, especially in a multi-threaded environment.
The factory design pattern “manufactures” the required type of product on demand.
You should consider using the abstract factory design pattern when you have a family of objects to be created.
A DAO design pattern essentially separates your core business logic from your persistence logic.

Generics

Generics will ensure that any attempts to add elements of types other than the specified type(s) will be caught at compile time itself. Hence, generics offer generic implementation with type safety.
Java 7 introduced diamond syntax where the type parameters (after new operator and class name) can be omitted. The compiler will infer the types from the type declaration.
Generics are not covariant. That is, subtyping doesn’t work with generics; you cannot assign a derived generic type parameter to a base type parameter.
The <?> specifies an unknown type in generics and is known as a wildcard. For example, List<?> refers to list of unknowns.
Wildcards can be bounded. For example, <? extends Runnable> specifies that ? can match any type as long as it is Runnable or any of its derived types. Note that extends is inclusive, so you can replace X in ? extends X. However, in <? super Runnable> , ? would match only the super types of Runnable, and Runnable itself will not match (i.e., it is an exclusive clause).
You use the extends keyword for both class type as well as an interface when specifying bounded types in generics. For specifying multiple base types, you use the & symbol. For example, in List<? extends X & Y>, ? will match types, extending both the types X and Y.

Collections Framework

Avoid mixing raw types with generic types. In other cases, make sure of the type safety manually.
The terms Collection, Collections, and collection are different.
Collection— java.util.Collection<E>—is the root interface in the collection hierarchy.
Collections—java.util.Collections—is a utility class that contains only static methods. The general term collection(s) refers to containers like map, stack, queue, etc.
The container classes store references to objects, so you cannot use primitive types with any of the collection classes.
The methods hashCode() and equals() need to be consistent for a class. For practical purposes, ensure that you follow this one rule: the hashCode() method should return the same hash value for two objects if the equals() method returns true for them.
If you’re using an object in containers like HashSet or HashMap, make sure you override the hashCode() and equals() methods correctly.
The Map interface does not extend the Collection interface.
It is not recommended that you store null as an argument, since there are methods in the Deque interface that return null, and it would be difficult for you to distinguish between the success or failure of the method call.
Implement the Comparable interface for your classes where a natural order is possible. If you want to compare the objects other than the natural order or if there is no natural ordering present for your class type, then create separate classes implementing the Comparator interface. Also, if you have multiple alternative ways to decide the order, then go for the
Comparator interface.

Searching, Parsing, and Building Strings

You can use the overloaded versions of the method indexOf() in the String class for forward searching in a string, lastIndexOf() for backward searching a string, and regionMatches() for comparing a “region” of text within a string.
To convert from a primitive type value to String type object, you can make use of the overloaded valueOf() method, which takes a primitive type value as an argument and returns the String object. To convert from the String type object to a primitive type value, you can make use of the parse methods available for primitive types in the corresponding wrapper types of the primitive types.
For parsing a string, you can use the split() method available in the String class. It takes a delimiter as an argument, and this argument is a regular expression.

Regular Expressions

A regular expression defines a search pattern that can be used to execute operations such as string search and string manipulation.
Use the Pattern and Matcher classes whenever you are performing search or replace on strings heavily; they are more efficient and faster than any other way to perform search/replace in Java.
You can form groups within a regex. These groups can be used to specify quantifiers on a desired subset of the whole regex. These groups can also be used to specify back reference.

String Formatting

The method printf() (and the method format() in the String class) uses string formatting flags to format strings.
Each format specifier starts with the % sign; followed by flags, width, and precision information; and ending with a data type specifier. In this string, the flags, width, and precision information are optional but the % sign and data type specifier are mandatory.

Reading and Writing Data to Console

You can obtain a reference to the console using the System.console() method; if the JVM is not associated with any console, this method will fail and return null.
Many methods are provided in Console-support formatted I/O. You can use the printf() and format() methods available in the Console class to print formatted text; the overloaded readLine() and readPassword() methods take format strings as arguments.
• Use the readPassword() method for reading secure strings such as passwords. It is recommended to use Array’s fill() method to “empty” the password read into the character array (to avoid malicious access to the typed passwords).
• The methods in the Console class have better support for special characters compared to printing text through PrintStreams.

Read and Write to Files with Streams

The java.io package has classes supporting both character streams and byte streams.
You can use character streams for text-based I/O. Byte streams are used for data-based I/O.
Character streams for reading and writing are called readers and writers respectively (represented by the abstract classes of Reader and Writer).
Byte streams for reading and writing are called input streams and output streams respectively (represented by the abstract classes of InputStream and OutputStream).
You should only use character streams for processing text files (or human-readable files), and byte streams for data files. If you try using one type of stream instead of another, your program won’t work as you would expect; even if it works by chance, you’ll get nasty bugs. So don’t mix up streams, and use the right stream for a given task at hand.
For both byte and character streams, you can use buffering. The buffer classes are provided as wrapper classes for the underlying streams. Using buffering will speed up the I/O when performing bulk I/O operations.
For processing data with primitive data types and strings, you can use data streams.
Serialization: The process of converting the objects in memory into a series of bytes.
Persistence: The mechanism of storing objects in memory into files.
You can use object streams for object persistence (i.e., reading and writing objects in memory to files and vice versa).


Working with the Path Class

A Path object is a programming abstraction to represent a path of a file/directory.
You can get an instance of Path using the get() method of the Paths class.
Path provides two methods to use to compare Path objects: equals() and compareTo(). Even if two Path objects point to the same file/directory, it is not guaranteed that you will get true from the equals() method.

Performing Operations on Files/Directories

You can check the existence of a file using the exists() method of the Files class.
The Files class provides the methods isReadable(), isWriteable(), and isExecutable() to check the ability of the program to read, write, or execute programmatically.
You can retrieve attributes of a file using the getAttributes() method.
You can use the readAttributes() method of the Files class to read attributes of a file in bulk.
The method copy() can be used to copy a file from one location to another. Similarly, the method move() can be used to move a file from one location to another.
While copying, all the directories (except the last one if you are copying a directory) in the specified path must exist to avoid NoSuchFileException.
Use the delete() method to delete a file; use the deleteIfExists() method to delete a file only if it exists.

Walking a File Tree

The Files class provides two flavors of walkFileTree() to enable you to walk through a file system.
The FileVisitor interface allows you to perform certain operations at certain key junctures.
If you do not want to implement all four methods in the FileVisitor interface, you can simply extend your implementation from the SimpleFileVisitor class.

Finding a File

The PathMatcher interface is useful when you want to find a file satisfying a certain pattern.
You can specify the pattern using glob or regex. Watching a Directory for Changes
Java 7 offers a directory watch service that can notify you when the file you are working on is changed by some other program.
You can register a Path object using a watch service along with certain event types. Whenever any file in the specified directory changes, an event is sent to the registered program.

Define the Layout of the JDBC API

JDBC (Java Database Connectivity) APIs provided by Java are meant for programmatic access to DataBase Management Systems (DBMSs).
JDBC hides all the heterogeneity of all the DBMSs and offers a single set of APIs to interact with all types of databases.
The complexity of heterogeneous interactions is delegated to JDBC driver manager and
JDBC drivers; hence all the details and complications are hidden by the JDBC API from the application developer.

• There are four types of drivers:
• Type 1 (JDBC-ODBC bridge drivers): JDBC driver calls ODBC (Open Database Connectivity) native calls using the Java Native Interface (JNI).
• Type 2 (Native-API drivers): These drivers use client-side libraries of a specific database and convert JDBC calls to native database calls.
• Type 3 (Network-protocol drivers): These drivers call database middleware and the middleware actually converts JDBC calls to database-specific native calls.
• Type 4 (Native-protocol drivers): The driver directly makes database-specific calls over the network without any support of additional client-side libraries.

Connect to a Database by Using a JDBC driver

The java.sql.Connection interface provides a channel through which the application and the database communicate.
The getConnection() method in the DriverManager class takes three arguments: the URL string, username string, and password string.
The syntax of the URL (which needs to be specified to get the Connection object) is <protocol>:<subprotocol>://<server>:<port>/. An example of a URL string is
jdbc:mysql://localhost:3306/. The <protocol> jdbc is the same for all DBMSs;
<subprotocol> will differ for each DBMS, <server> depends on the location in which you host the database, and each DBMS uses a specific <port> number.
If the JDBC API is not able to locate the JDBC driver, it will throw a SQLException. If there are jars for the drivers available, they need to be included in the classpath to enable the JDBC API to locate the driver.
Prior to JDBC 4.0, you would have to explicitly load the JDBC driver using the
Class.forName() statement; with JDBC 4.0 and above, this statement is not needed and the
JDBC API will load the driver from the details given in the URL string.

Update and Query a Database

JDBC supports two interfaces for querying and updating: Statement and Resultset.
A Statement is a SQL statement that can be used to communicate a SQL statement to the connected database and receive results from the database. There are three types of Statements:
Statement: You need to use Statement when you need to send a SQL statement to the database without any parameter.
PreparedStatement: Represents a precompiled SQL statement that can be customized using IN parameters.
CallableStatement: Used to execute stored procedures; can handle IN as well as OUT and INOUT parameters.
A ResultSet is a table with column heading and associated values requested by the query.
A ResultSet object maintains a cursor pointing to the current row. Initially, the cursor is set to just before the first row; calling the next() method advances the cursor position by one row.
• The column index in the ResultSet object starts from 1 (not from 0).
• You need to call updateRow() after modifying the row contents in a ResultSet; otherwise changes made to the ResultSet object will be lost.
• By calling the getMetaData() method in the Connection interface, you can examine the capabilities of the underlying database.

Customize the Transaction Behavior of JDBC and Commit Transactions

A transaction is a set of SQL operations that needs to be either executed all successfully or not at all.
Transaction-related methods are supported in the Connection interface.
By default auto-commit mode is set to true, so all changes you make through the connection are committed automatically to the database.
You can use setAutoCommit(false); to enable manual commits. With auto-commit not enabled, you need to explicitly commit or rollback transactions.
If the commit() method does not execute in manual commit mode, there will be no change in the database.
You can divide a big transaction into multiple milestones. These milestones are referred to as savepoints. This way you may save the changes to a database up to a milestone once the milestone is achieved.

Use the JDBC 4.1 RowSetProvider, RowSetFactory, and RowSet Interfaces

RowSet is a special ResultSet that supports the JavaBean component model.
JdbcRowSet is a connected RowSet while other subinterfaces of RowSet (i.e., JoinRowSet, CachedRowSet, WebRowSet, and FilteredRowSet) are disconnected RowSets.
RowSetProvider provides APIs to get a RowSetFactory implementation, which can in turn be used to instantiate a relevant RowSet implementation.

Introduction to Exception Handling

When an exception is thrown from a try block, the JVM looks for a matching catch handler from the list of catch handlers in the method call-chain. If no matching handler is found, that unhandled exception will result in crashing the application.
While providing multiple exception handlers (stacked catch handlers), specific exception handlers should be provided before general exception handlers. Providing base exception handlers before the derived handlers will result in a compiler error.
You can programmatically access the stack trace using the methods such as printStackTrace() and getStackTrace(), which can be called on any exception object.
A try block can have multiple catch handlers. If the cause of two or more exceptions is similar, and the handling code is also similar, you can consider combining the handlers and make it into a multi-catch block.
The code inside a finally block will be executed irrespective of whether a try block has successfully executed or resulted in an exception. This makes a finally block the most suitable place to release resources, such as file handles, data base handles, network streams, etc.

Try-with-Resources

Forgetting to release resources by explicitly calling the close() method is a common mistake.
You can use a try-with-resources statement to simplify your code and auto-close resources.
For a resource to be usable in a try-with-resources statement, the class of that resource must implement the java.lang.AutoCloseable interface and define the close() method.
You can auto-close multiple resources within a try-with-resources statement. These resources need to be separated by semicolons in the try-with-resources statement header.
Because you can use multiple resources within a try-with-resources statement, the possibility of more than one exception getting thrown from the try block and the finally block is high.
If a try block throws an exception, and a finally block also throws exception(s), then the exceptions thrown in the finally block will be added as suppressed exceptions to the exception that gets thrown out of the try block to the caller.

Exception Types

The class Throwable is the root class of the exception hierarchy. Only Throwable and its derived classes can be used with Java exception handling keywords such as try, catch, and throws.
The Exception class (except its sub-hierarchy of the RuntimeException class) and its derived classes are known as checked exceptions. These exceptions represent exceptional conditions that can be reasonably expected to occur when the program executes, hence they must be handled. A method that contains some code segment that can throw a checked exception must either provide a catch handler to handle it or declare that exception in its throws clause.

• The RuntimeException and Error classes and derived classes are known as unchecked exceptions. They can be thrown anywhere in the program (without being declared that the segment of code can throw these exceptions).
• The RuntimeException classes and derived classes represent programming mistakes (logical mistakes) and are not generally expected to be caught and handled in the program. However, in some cases, it is meaningful to handle these exceptions in catch blocks.

• The Error classes and derived classes represent exceptions that arise because of JVM errors; either the JVM has detected a serious abnormal condition or has run out of resources. When an Error occurs, the typical best course of action is to terminate the program.
• A catch block should either handle the exception or rethrow it. To hide or swallow an exception by catching an exception and doing nothing is really a bad practice.

Throws Clause

The throws clause for a method is meant for listing the checked exceptions that the method body can throw.
Static initialization blocks cannot throw any checked exceptions. Non-static initialization blocks can throw checked exceptions; however, all the constructors should declare that exception in their throws clause.
A method’s throws clause is part of the contract that its overriding methods in derived classes should obey. An overriding method can provide the same throw clause as the base method’s throws clause or a more specific throws clause than the base method’s throws clause. The overriding method cannot provide a more general throws clause or declare to throw additional checked exceptions when compared to the base method’s throws clause.

Custom Exceptions

You can define your own exception classes (known as custom exceptions) in your programs.
It is recommended that you derive custom exceptions from either the Exception or RuntimeException class. Creation of custom exceptions by extending the Throwable class (too generic) or the Error class (exceptions of this type are reserved for JVM and the Java APIs to throw) is not recommended.
You can wrap one exception and throw it as another exception. These two exceptions become chained exceptions. From the thrown exception, you can get the cause of the exception.


Assertions

Assertions are condition checks in the program and are meant to be used for explicitly checking the assumptions you make while writing programs.
The assert statement is of two forms: one that takes a Boolean argument and one that takes an additional string argument.
If the Boolean condition given in the assert argument fails (i.e., evaluates to false), the program will terminate after throwing an AssertionError. It is not advisable to catch and recover from when an AssertionError is thrown by the program.
By default, assertions are disabled at runtime. You can use the command-line arguments of –ea (for enabling asserts) and –da (for disabling asserts) and their variants when you invoke the JVM.

Read and Set the Locale Using the Locale Object

A locale represents a language, culture, or country; the Locale class in Java provides an abstraction for this concept.
Each locale can have three entries: the language, country, and variant. You can use standard codes available for language and country to form locale tags. There are no standard tags for variants; you can provide variant strings based on your need.
The getter methods in the Locale class—such as getLanguage(), getCountry(), and getVariant()—return codes; whereas the similar methods of getDisplayCountry(), getDisplayLanguage(), and getDisplayVariant() return names.
The getDefault() method in Locale returns the default locale set in the JVM. You can change this default locale to another locale by using the setDefault() method.
There are many ways to create or get a Locale object corresponding to a locale:
Use the constructor of the Locale class.
Use the forLanguageTag(String languageTag) method in the Locale class.
Build a Locale object by instantiating Locale.Builder and then call setLanguageTag() from that object.
Use the predefined static final constants for locales in the Locale class.

Build a Resource Bundle for Each Locale

A resource bundle is a set of classes or property files that help define a set of keys and map those keys to locale-specific values.
The class ResourceBundle has two derived classes: PropertyResourceBundle and ListResourceBundle. You can use ResourceBundle.getBundle() to automatically load a bundle for a given locale.
• The PropertyResourceBundle class provides support for multiple locales in the form of property files. For each locale, you specify the keys and values in a property file for that locale.
You can use only Strings as keys and values.
• To add support for a new locale, you can extend the ListResourceBundle class. In this derived class, you have to override the Object [][] getContents() method. The returned array must have the list of keys and values. The keys must be Strings, and values can be any objects.
• When passing the key string to the getObject() method to fetch the matching value in the resource bundle, make sure that the passed keys and the key in the resource bundle exactly match (the keyname is case sensitive). If they don’t match, you’ll get a MissingResourceException.
• The naming convention for a fully qualified resource bundle name is packagequalifier.bundlename + "_" + language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions.

Load a Resource Bundle in an Application

The process of finding a matching resource bundle is same for classes extended from ListResourceBundles as for property files defined for PropertyResourceBundles.
Here is the search sequence to look for a matching resource bundle. Search starts from Step
1. If at any step the search finds a match, the resource bundle is loaded. Otherwise, the search proceeds to the next step.
Step 1: The search starts by looking for an exact match for the resource bundle with the full name.
Step 2: The last component (the part separated by _) is dropped and the search is repeated with the resulting shorter name. This process is repeated till the last locale modifier is left.
Step 3: The search is restarted using the full name of the bundle for the default locale.
Step 4: Search for the resource bundle with just the name of the bundle.
Step 5: The search fails, throwing a MissingBundleException.
The getBundle() method takes a ResourceBundle.Control object as an additional parameter.
By extending this ResourceBundle.Control class and passing that object, you can control or customize the resource bundle searching and loading process.

Format Text for Localization Using NumberFormat and DateFormat

To handle date and time, numbers, and currencies in a culture-sensitive way, you can use the
java.text.Format class and its two main derived classes NumberFormat and DateFormat for that.
The NumberFormat class provides support locale-sensitive handling of numbers relating to how thousands are separated, treating a number as a currency value, etc.
The NumberFormat class provides methods to format or parse numbers. “Formatting” means converting a numeric value to a textual form suitable for displaying to users; “parsing” means converting a number back to numeric form for use in the program. The parse() method returns a Number if successful—otherwise it throws ParseException (a checked exception).
NumberFormat has many factory methods: getInstance(), getCurrencyInstance(),
getIntegerInstance(), and getPercentInstance().
• The Currency class provides support for handling currency values in a locale-sensitive way.
• The DateFormat class provides support for processing date and time in a locale-sensitive manner.
• The DateFormat has three overloaded factory methods—getDateInstance(),
getTimeInstance(), and getDateTimeInstance()—that return DateFormat instances for processing date, time, and both date and time, respectively.
• SimpleDateFormat (derived from DateFormat) uses the concept of a pattern string to support custom formats for date and time.
• You encode the format of the date or time using case-sensitive letters to form a date or time pattern string.

Introduction to Concurrent Programming

You can create c lasses that are capable of multi-threading by implementing the Runnable interface or by extending the Thread class.
Always implement the run() method. The default run() method in Thread does nothing.
Call the start() method and not the run() method directly in code. (Leave it to the JVM to call the run() method.)
Every thread has a thread name, priority, and thread-group associated with it; the default toString() method implementation in Thread prints them.
If you call the sleep() method of a thread, the thread does not release the lock and it holds on to the lock.
You can use the join() method to wait for another thread to terminate.
In general, if you are not using the “interrupt” feature in threads, it is safe to ignore
InterruptedException; however it’s better still to log or print the stack trace if that exception occurs.
Threads execute asynchronously; you cannot predict the order in which the threads run.
Threads are also non-deterministic: in many cases, you cannot reproduce problems like deadlocks or data races every time.

Thread States

There are three basic thread states: new, runnable, and terminated. When a thread is just created, it is in a new state; when it is ready to run or running, it is in a runnable state. When the thread dies, it’s in terminated state.
The runnable state has two states internally (at the OS level): ready and running states.
A thread will be in the blocked state when waiting to acquire a lock. The thread will be in the timed_waiting state when a timeout is given for calls like wait. The thread will be in the waiting state when, for example, wait() is called (without a time out value).
You will get an IllegalThreadStateException if your operations result in invalid thread state transitions.

Concurrent Access Problems

Concurrent reads and writes to resources may lead to the data race problem.
You must use thread synchronization (i.e., locks) to access shared values and avoid data races. Java provides thread synchronization features to provide protected access to shared resources—namely, synchronized blocks and synchronized methods.
Using locks can introduce problems such as deadlocks. When a deadlock happens, the process will hang and will never terminate.
A deadlock typically happens when two threads acquire locks in opposite order. When one thread has acquired one lock and waits for another lock, another thread has acquired that other lock and waits for the first lock to be released. So, no progress is made and the program deadlocks.
To avoid deadlocks, it is better to avoid acquiring multiple locks. When you have to acquire such multiple locks, ensure that they are acquired in the same order in all places in the program.

The Wait/Notify Mechanism

When a thread has to wait for a particular condition or event to be satisfied by another thread, you can use a wait/notify mechanism as a communication mechanism between threads.
When a thread needs to wait for a particular condition/event, you can either call wait() with or without a timeout value specified.
To a oid notifications getting lost, it is better to always use notifyAll() instead of notify().


Using java.util.concurrent Collections

A semaphore controls access to shared resources. A semaphore maintains a counter to specify number of resources that the semaphore controls.
CountDownLatch allows one or more threads to wait for a countdown to complete.
The Exchanger class is meant for exchanging data between two threads. This class is useful when two threads need to synchronize between each other and continuously exchange data.
CyclicBarrier helps provide a synchronization point where threads may need to wait at a predefined execution point until all other threads reach that point.
Phaser is a useful feature when few independent threads have to work in phases to complete a task.

Applying Atomic Variables and Locks

Java pr ovides an efficient alternative in the form of atomic variables where one needs to acquire and release a lock just to carry out primitive operations on variables.
A lock ensures that only one thread accesses a shared resource at a time.
A Condition supports thread notification mechanism. When a certain condition is not satisfied, a thread can wait for another thread to satisfy that condition; that other thread could notify once the condition is met.

Using Executors and ThreadPools

The Executors hierarchy abstracts the lower-level details of multi-threaded programming and offers high-level user-friendly concurrency constructs.
The Callable interface represents a task that needs to be completed by a thread. Once the task completes, the call() method of a Callable implementation returns a value.
A thread pool is a collection of threads that can execute tasks.
Future represents objects that contain a value that is returned by a thread in the future.
ThreadFactory is an interface that is meant for creating threads instead of explicitly creating threads by calling a new Thread().

Using the Parallel Fork/Join Framework

The Fork/Join framework is a portable means of executing a program with decent parallelism.
The framework is an implementation of the ExecutorService interface and provides an easy-to-use concurrent platform in order to exploit multiple processors.
This framework is very useful for modeling divide-and-conquer problems.
The Fork/Join framework uses the work-stealing algorithm: when a worker thread completes its work and is free, it takes (or “steals”) work from other threads that are still busy doing some work.
The work-stealing technique results in decent load balancing thread management with minimal synchronization cost.
ForkJoinPool is the most important class in the Fork/Join framework. It is a thread pool for running fork/join tasks—it executes an instance of ForkJoinTask. It executes tasks and manages their lifecycles.
ForkJoinTask<V> is a lightweight thread-like entity representing a task that defines methods such as fork() and join().

About This Site

Howdy! My name is Suersh Rohan and I am the developer and maintainer of this blog. It mainly consists of my thoughts and opinions on the technologies I learn,use and develop with.
Powered by Blogger.

- Copyright © My Code Snapshots -Metrominimalist- Powered by Blogger - Designed by Suresh Rohan -