Difference between SQL and NoSQL

Prerequisites – SQLNoSQL
When it comes to choosing a database the biggest decisions is picking a relational (SQL) or non-relational (NoSQL) data structure. While both the databases are viable options still there are certain key differences between the two that users must keep in mind when making a decision.

The Main Differences:

  1. Type –
    SQL databases are primarily called as Relational Databases (RDBMS); whereas NoSQL database are primarily called as non-relational or distributed database.
  2. Language –
    SQL databases defines and manipulates data based structured query language (SQL). Seeing from a side this language is extremely powerful. SQL is one of the most versatile and widely-used options available which makes it a safe choice especially for great complex queries. But from other side it can be restrictive. SQL requires you to use predefined schemas to determine the structure of your data before you work with it. Also all of your data must follow the same structure. This can require significant up-front preparation which means that a change in the structure would be both difficult and disruptive to your whole system.

    A NoSQL database has dynamic schema for unstructured data. Data is stored in many ways which means it can be document-oriented, column-oriented, graph-based or organized as a KeyValue store. This flexibility means that documents can be created without having defined structure first. Also each document can have its own unique structure. The syntax varies from database to database, and you can add fields as you go.

  3. The Scalability –
    In almost all situations SQL databases are vertically scalable. This means that you can increase the load on a single server by increasing things like RAM, CPU or SSD. But on the other hand NoSQL databases are horizontally scalable. This means that you handle more traffic by sharding, or adding more servers in your NoSQL database. It is similar to adding more floors to the same building versus adding more buildings to the neighborhood. Thus NoSQL can ultimately become larger and more powerful, making these databases the preferred choice for large or ever-changing data sets.
    The Structure –
    SQL databases are table-based on the other hand NoSQL databases are either key-value pairs, document-based, graph databases or wide-column stores. This makes relational SQL databases a better option for applications that require multi-row transactions such as an accounting system or for legacy systems that were built for a relational structure.
  4. Property followed –
    SQL databases follow ACID properties (Atomicity, Consistency, Isolation and Durability) whereas the NoSQL database follows the Brewers CAP theorem (Consistency, Availability and Partition tolerance).
  5. Support –
    Great support is available for all SQL database from their vendors. Also a lot of independent consultations are there who can help you with SQL database for a very large scale deployments but for some NoSQL database you still have to rely on community support and only limited outside experts are available for setting up and deploying your large scale NoSQL deployments.

    Some examples of SQL databases include PostgreSQL, MySQL, Oracle and Microsoft SQL Server. NoSQL database examples include Redis, RavenDB Cassandra, MongoDB, BigTable, HBase, Neo4j and CouchDB.

Key highlights on SQL vs NoSQL:

SQL NOSQL
RELATIONAL DATABASE MANAGEMENT SYSTEM (RDBMS) Non-relational or distributed database system.
These databases have fixed or static or predefined schema They have have dynamic schema
These databases are not suited for hierarchical data storage. These databases are best suited for hierarchical data storage.
These databases are best suited for complex queries These databases are not so good for complex queries
Verticlly Scalable Horizontally scalable

Monolithic vs. Microservices Architecture

When developing a server-side application you can start it with a modular hexagonal or layered architecture which consists of different types of components:

  • Presentation — responsible for handling HTTP requests and responding with either HTML or JSON/XML (for web services APIs).
  • Business logic — the application’s business logic.
  • Database access — data access objects responsible for access the database.
  • Application integration — integration with other services (e.g. via messaging or REST API).

Despite having a logically modular architecture, the application is packaged and deployed as a monolith. Benefits of Monolithic Architecture

  • Simple to develop.
  • Simple to test. For example you can implement end-to-end testing by simply launching the application and testing the UI with Selenium.
  • Simple to deploy. You just have to copy the packaged application to a server.
  • Simple to scale horizontally by running multiple copies behind a load balancer.

In the early stages of the project it works well and basically most of the big and successful applications which exist today were started as a monolith.

Drawbacks of Monolithic Architecture

  • This simple approach has a limitation in size and complexity.
  • Application is too large and complex to fully understand and made changes fast and correctly.
  • The size of the application can slow down the start-up time.
  • You must redeploy the entire application on each update.
  • Impact of a change is usually not very well understood which leads to do extensive manual testing.
  • Continuous deployment is difficult.
  • Monolithic applications can also be difficult to scale when different modules have conflicting resource requirements.
  • Another problem with monolithic applications is reliability. Bug in any module (e.g. memory leak) can potentially bring down the entire process. Moreover, since all instances of the application are identical, that bug will impact the availability of the entire application.
  • Monolithic applications has a barrier to adopting new technologies. Since changes in frameworks or languages will affect an entire application it is extremely expensive in both time and cost.

Microservices Architecture

The idea is to split your application into a set of smaller, interconnected services instead of building a single monolithic application. Each microservice is a small application that has its own hexagonal architecture consisting of business logic along with various adapters. Some microservices would expose a REST, RPC or message-based API and most services consume APIs provided by other services. Other microservices might implement a web UI.

The Microservice architecture pattern significantly impacts the relationship between the application and the database. Instead of sharing a single database schema with other services, each service has its own database schema. On the one hand, this approach is at odds with the idea of an enterprise-wide data model. Also, it often results in duplication of some data. However, having a database schema per service is essential if you want to benefit from microservices, because it ensures loose coupling. Each of the services has its own database. Moreover, a service can use a type of database that is best suited to its needs, the so-called polyglot persistence architecture.

Some APIs are also exposed to the mobile, desktop, web apps. The apps don’t, however, have direct access to the back-end services. Instead, communication is mediated by an intermediary known as an API Gateway. The API Gateway is responsible for tasks such as load balancing, caching, access control, API metering, and monitoring.

The Microservice architecture pattern corresponds to the Y-axis scaling of the Scale Cube model of scalability.

Benefits of Microservices Architecture

  • It tackles the problem of complexity by decomposing application into a set of manageable services which are much faster to develop, and much easier to understand and maintain.
  • It enables each service to be developed independently by a team that is focused on that service.
  • It reduces barrier of adopting new technologies since the developers are free to choose whatever technologies make sense for their service and not bounded to the choices made at the start of the project.
  • Microservice architecture enables each microservice to be deployed independently. As a result, it makes continuous deployment possible for complex applications.
  • Microservice architecture enables each service to be scaled independently.

Drawbacks of Microservices Architecture

  • Microservices architecture adding a complexity to the project just by the fact that a microservices application is a distributed system. You need to choose and implement an inter-process communication mechanism based on either messaging or RPC and write code to handle partial failure and take into account other fallacies of distributed computing.
  • Microservices has the partitioned database architecture. Business transactions that update multiple business entities in a microservices-based application need to update multiple databases owned by different services. Using distributed transactions is usually not an option and you end up having to use an eventual consistency based approach, which is more challenging for developers.
  • Testing a microservices application is also much more complex then in case of monolithic web application. For a similar test for a service you would need to launch that service and any services that it depends upon (or at least configure stubs for those services).
  • It is more difficult to implement changes that span multiple services. In a monolithic application you could simply change the corresponding modules, integrate the changes, and deploy them in one go. In a Microservice architecture you need to carefully plan and coordinate the rollout of changes to each of the services.
  • Deploying a microservices-based application is also more complex. A monolithic application is simply deployed on a set of identical servers behind a load balancer. In contrast, a microservice application typically consists of a large number of services. Each service will have multiple runtime instances. And each instance need to be configured, deployed, scaled, and monitored. In addition, you will also need to implement a service discovery mechanism. Manual approaches to operations cannot scale to this level of complexity and successful deployment a microservices application requires a high level of automation.

Summary

Building complex applications is inherently difficult. A Monolithic architecture better suits simple, lightweight applications. There are opinions which suggest to start from the monolith first and others which recommend not to start with monolith when your goal is a microservices architecture. But anyway it is important to understand Monolithic architecture since it is the basis for microservices architecture where each service by itself is implemented according to monolithic architecture. The Microservices architecture pattern is the better choice for complex, evolving applications. Actually the microservices approach is all about handling a complex system, but in order to do so the approach introduces its own set of complexities and implementation challenges.

Optimistic vs. Pessimistic locking

Optimistic Locking is a strategy where you read a record, take note of a version number (other methods to do this involve dates, timestamps or checksums/hashes) and check that the version hasn’t changed before you write the record back. When you write the record back you filter the update on the version to make sure it’s atomic. (i.e. hasn’t been updated between when you check the version and write the record to the disk) and update the version in one hit.

If the record is dirty (i.e. different version to yours) you abort the transaction and the user can re-start it.

This strategy is most applicable to high-volume systems and three-tier architectures where you do not necessarily maintain a connection to the database for your session. In this situation the client cannot actually maintain database locks as the connections are taken from a pool and you may not be using the same connection from one access to the next.

Pessimistic Locking is when you lock the record for your exclusive use until you have finished with it. It has much better integrity than optimistic locking but requires you to be careful with your application design to avoid Deadlocks. To use pessimistic locking you need either a direct connection to the database (as would typically be the case in a two tier client server application) or an externally available transaction ID that can be used independently of the connection.

In the latter case you open the transaction with the TxID and then reconnect using that ID. The DBMS maintains the locks and allows you to pick the session back up through the TxID. This is how distributed transactions using two-phase commit protocols (such as XA or COM+ Transactions) work

 

====================================================

Transactional isolation is usually implemented by locking whatever is accessed in a transaction. There are two different approaches to transactional locking: Pessimistic locking and optimistic locking.

The disadvantage of pessimistic locking is that a resource is locked from the time it is first accessed in a transaction until the transaction is finished, making it inaccessible to other transactions during that time. If most transactions simply look at the resource and never change it, an exclusive lock may be overkill as it may cause lock contention, and optimistic locking may be a better approach. With pessimistic locking, locks are applied in a fail-safe way. In the banking application example, an account is locked as soon as it is accessed in a transaction. Attempts to use the account in other transactions while it is locked will either result in the other process being delayed until the account lock is released, or that the process transaction will be rolled back. The lock exists until the transaction has either been committed or rolled back.

With optimistic locking, a resource is not actually locked when it is first is accessed by a transaction. Instead, the state of the resource at the time when it would have been locked with the pessimistic locking approach is saved. Other transactions are able to concurrently access to the resource and the possibility of conflicting changes is possible. At commit time, when the resource is about to be updated in persistent storage, the state of the resource is read from storage again and compared to the state that was saved when the resource was first accessed in the transaction. If the two states differ, a conflicting update was made, and the transaction will be rolled back.

In the banking application example, the amount of an account is saved when the account is first accessed in a transaction. If the transaction changes the account amount, the amount is read from the store again just before the amount is about to be updated. If the amount has changed since the transaction began, the transaction will fail itself, otherwise the new amount is written to persistent storage.

 

Spring MVC Content Negotiation :: How to make a resource accept both xml and json as input.

1. Overview

This article describes how to implement content negotiation in a Spring MVC project.

Generally, there are three options to determine the media type of a request:

  • Using URL suffixes (extensions) in the request (eg .xml/.json)
  • Using URL parameter in the request (eg ?format=json)
  • Using Accept header in the request

By default, this is the order in which the Spring content negotiation manager will try to use these three strategies. And if none of these are enabled, we can specify a fallback to a default content type.

2. Content Negotiation Strategies

Let’s start with the necessary dependencies – we are working with JSON and XML representations, so for this article we’ll use Jackson for JSON:

1
2
3
4
5
6
7
8
9
10
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.2</version>
</dependency>

For XML support we can use either JAXB, XStream or the newer Jackson-XML support.

Since we have explained the use of the Accept header in an earlier article on HttpMessageConverterslet’s focus on the first two strategies in depth.

3. The URL Suffix Strategy

By default, this strategy is disabled, but the framework can check for a path extension right from the URL to determine the output content type.

Before going into configurations, let’s have a quick look at an example. We have the following simple API method implementation in a typical Spring controller:

1
2
3
4
5
6
7
@RequestMapping(
  value = "/employee/{id}",
  produces = { "application/json", "application/xml" },
  method = RequestMethod.GET)
public @ResponseBody Employee getEmployeeById(@PathVariable long id) {
    return employeeMap.get(id);
}

Let’s invoke it making use of the JSON extension to specify the media type of the resource:

1
curl http://localhost:8080/spring-mvc-java/employee/10.json

Here’s what we might get back if we use a JSON extension:

1
2
3
4
5
{
    "id": 10,
    "name": "Test Employee",
    "contactNumber": "999-999-9999"
}

And here’s what the request – response will look like with XML:

1
curl http://localhost:8080/spring-mvc-java/employee/10.xml

The response body:

1
2
3
4
5
<employee>
    <contactNumber>999-999-9999</contactNumber>
    <id>10</id>
    <name>Test Employee</name>
</employee>

Now:

Now if we do not use any extension or use one that is not configured – the default content type will be returned:

1
curl http://localhost:8080/spring-mvc-java/employee/10

Let’s now have a look at setting up this strategy – both with Java and XML configurations.

3.1. Java Configuration

1
2
3
4
5
6
7
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true).
    favorParameter(false).
    ignoreAcceptHeader(true).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON);
}

Let’s go over the details.

First, we’re enabling the path extensions strategy.

Then, we’re disabling the URL parameter strategy as well as the Accept header strategy – because we want to only rely on the path extension way of determining the type of the content.

We’re then turning off the Java Activation Framework; JAF can be used as a fallback mechanism to select the output format if the incoming request is not matching any of the strategies we configured. We’re disabling it because we’re going to configure JSON as the default content type.

And finally – we are setting up JSON to be the default. That means if none of the two strategies are matched, all incoming request will be mapped to a controller method that serves JSON.

3.2. XML Configuration

Let’s also have a quick look at the same exact configuration, only using XML:

1
2
3
4
5
6
7
8
<bean id="contentNegotiationManager"
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="true" />
    <property name="favorParameter" value="false"/>
    <property name="ignoreAcceptHeader" value="true" />
    <property name="defaultContentType" value="application/json" />
    <property name="useJaf" value="false" />
</bean>

4. The URL Parameter Strategy

We’ve used path extensions in the previous section – let’s now set up Spring MVC to make use of a path parameter.

We can enable this strategy by setting the value of the property favorParameter to true.

Let’s have a quick look at how that would work with our previous example:

1
curl http://localhost:8080/spring-mvc-java/employee/10?mediaType=json

And here’s what the JSON response body will be:

1
2
3
4
5
{
    "id": 10,
    "name": "Test Employee",
    "contactNumber": "999-999-9999"
}

If we use XML parameter, the output will be in XML form:

1
curl http://localhost:8080/spring-mvc-java/employee/10?mediaType=xml

The response body:

1
2
3
4
5
<employee>
    <contactNumber>999-999-9999</contactNumber>
    <id>10</id>
    <name>Test Employee</name>
</employee>

Now let’s do the configuration – again, first using Java and then XML.

4.1. Java Configuration

1
2
3
4
5
6
7
8
9
10
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(false).
    favorParameter(true).
    parameterName("mediaType").
    ignoreAcceptHeader(true).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON).
    mediaType("xml", MediaType.APPLICATION_XML).
    mediaType("json", MediaType.APPLICATION_JSON);
}

Let’s read through this configuration.

First, of course the path extension and the Accept header strategies are disabled (as well as JAF).

The rest of the configuration is the same.

4.2. XML Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean id="contentNegotiationManager"
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="true"/>
    <property name="parameterName" value="mediaType"/>
    <property name="ignoreAcceptHeader" value="true" />
    <property name="defaultContentType" value="application/json" />
    <property name="useJaf" value="false" />
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
</bean>

Also we can have both strategies (extension and parameter) enabled at the same time:

1
2
3
4
5
6
7
8
9
10
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true).
    favorParameter(true).
    parameterName("mediaType").
    ignoreAcceptHeader(true).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON).
    mediaType("xml", MediaType.APPLICATION_XML).
    mediaType("json", MediaType.APPLICATION_JSON);
}

In this case Spring will look for path extension first, if that is not present then will look for path parameter. And if both of these are not available in the input request, then default content type will be returned back.

5. The Accept Header Strategy

If Accept header is enabled, Spring MVC will look for its value in the incoming request to determine the representation type.

We have to set the value of ignoreAcceptHeader to false to enable this approach and we’re disabling the other two strategies just so that we know we’re only relying on the Accept header.

5.1. Java Configuration

1
2
3
4
5
6
7
8
9
10
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true).
    favorParameter(false).
    parameterName("mediaType").
    ignoreAcceptHeader(false).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON).
    mediaType("xml", MediaType.APPLICATION_XML).
    mediaType("json", MediaType.APPLICATION_JSON);
}

5.2. XML Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean id="contentNegotiationManager"
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="true" />
    <property name="favorParameter" value="false"/>
    <property name="parameterName" value="mediaType"/>
    <property name="ignoreAcceptHeader" value="false" />
    <property name="defaultContentType" value="application/json" />
    <property name="useJaf" value="false" />
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
</bean>

Finally we need to switch on the content negotiation manager by plug-in it into the overall configuration:

1
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

6. Conclusion

And we’re done. We looked at how content negotiation works in Spring MVC and we focused on a few examples of setting that up to use various strategies to determine the content type.

The full implementation of this article can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.

Spring Bean Scopes

Spring Bean Scopes allows us to have more granular control of the bean instances creation. Sometimes we want to create bean instance as singleton but in some other cases we might want it to be created on every request or once in a session.

Spring Bean Scopes

There are five types of spring bean scopes:

  1. singleton – only one instance of the spring bean will be created for the spring container. This is the default spring bean scope. While using this scope, make sure bean doesn’t have shared instance variables otherwise it might lead to data inconsistency issues.
  2. prototype – A new instance will be created every time the bean is requested from the spring container.
  3. request – This is same as prototype scope, however it’s meant to be used for web applications. A new instance of the bean will be created for each HTTP request.
  4. session – A new bean will be created for each HTTP session by the container.
  5. global-session – This is used to create global session beans for Portlet applications.

Spring Bean Singleton and Prototype Scope

Spring bean singleton and prototype scopes can be used in standalone spring apps. Let’s see how we can easily configure these scopes using @Scope annotation.

Let’s say we have a java bean class.


package com.journaldev.spring;

public class MyBean {

	public MyBean() {
		System.out.println("MyBean instance created");
	}

}

Let’s define the spring configuration class where we will define the method to get MyBean instance from spring container.


package com.journaldev.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class MyConfiguration {
	
	@Bean
	@Scope(value="singleton")
    public MyBean myBean() {
		return new MyBean();
	}
	
}

Note that singleton is default scope, so we can remove @Scope(value="singleton") from above bean definition.

Now let’s create a main method and test the singleton scope.

package com.journaldev.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MySpringApp {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
		ctx.register(MyConfiguration.class);
		ctx.refresh();

		 MyBean mb1 = ctx.getBean(MyBean.class);
		 System.out.println(mb1.hashCode());

		 MyBean mb2 = ctx.getBean(MyBean.class);
		 System.out.println(mb2.hashCode());

		ctx.close();
	}

}

When above program is executed, we will get output like below.


MyBean instance created
867988177
867988177

Notice that both MyBean instances have same hashcode and the constructor is called once once, it means that spring container is returning the same instance of MyBean always.

Now let’s change the scope to prototype.


@Bean
@Scope(value="prototype")
public MyBean myBean() {
	return new MyBean();
}

This time we will get following output when main method is executed.


MyBean instance created
867988177
MyBean instance created
443934570

It’s clear that MyBean instance is created every time it’s requested from spring container.

Now let’s change the scope to request.


@Bean
@Scope(value="request")
public MyBean myBean() {
	return new MyBean();
}

In this case, we will get following exception.


Exception in thread "main" java.lang.IllegalStateException: No Scope registered for scope name 'request'
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:347)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1015)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1107)
	at com.journaldev.spring.MySpringApp.main(MySpringApp.java:12)

It’s because requestsession and global-session scopes are not available for standalone applications.

Spring Bean Request and Session Scope

For spring bean request and session scope example, we will create Spring Boot web application. Create a spring boot starter project and choose “web” so that we can run it as a web application.

spring boot starter project

Our final project will look like below image.

spring bean scopes spring boot web app project

ServletInitializer and SpringBootMvcApplication are auto generated spring boot classes. We don’t need to make any changes there.

Here is my pom.xml file, have a look at the dependencies for our application. Your pom.xml file might be slightly different based on the Eclipse version you are using.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.journaldev.spring</groupId>
	<artifactId>Spring-Boot-MVC</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>Spring-Boot-MVC</name>
	<description>Spring Beans Scope MVC</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>10</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

Let’s create some spring components and configure them as spring beans in the spring container with scope as request and session.

Spring Bean Request Scope


package com.journaldev.spring;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataRequestScope {

	private String name = "Request Scope";
	
	public DataRequestScope() {
		System.out.println("DataRequestScope Constructor Called");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Spring Bean Session Scope


package com.journaldev.spring;

import org.springframework.context.annotation.Scope;
import java.time.LocalDateTime;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataSessionScope {

	private String name = "Session Scope";
	
	public DataSessionScope() {
		System.out.println("DataSessionScope Constructor Called at "+LocalDateTime.now());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Spring Component

Now let’s create a spring component and use spring to auto configure above beans.


package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Customer {

	@Autowired
	private DataRequestScope dataRequestScope;
	
	@Autowired
	private DataSessionScope dataSessionScope;

	public DataRequestScope getDataRequestScope() {
		return dataRequestScope;
	}

	public void setDataRequestScope(DataRequestScope dataRequestScope) {
		this.dataRequestScope = dataRequestScope;
	}

	public DataSessionScope getDataSessionScope() {
		return dataSessionScope;
	}

	public void setDataSessionScope(DataSessionScope dataSessionScope) {
		this.dataSessionScope = dataSessionScope;
	}


}

Spring Rest Controller

Finally, let’s create a RestController class and configure some API end points for our testing purposes.


package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloData {

	@Autowired
	private Customer customer;
	
	@RequestMapping("/nameRS")
	public String helloRS() {
		return customer.getDataRequestScope().getName();
	}
	
	@RequestMapping("/nameSSUpdated")
	public String helloSSUpdated() {
		customer.getDataSessionScope().setName("Session Scope Updated");
		return customer.getDataSessionScope().getName();
	}
	
	@RequestMapping("/nameSS")
	public String helloSS() {
		return customer.getDataSessionScope().getName();
	}
}

Spring Boot Session Timeout Configuration

Finally we have to configure spring boot session timeout variables, add below properties in src/main/resources/application.properties.


server.session.cookie.max-age= 1
server.session.timeout= 1

Now our spring beans with session scope will be invalidated in one minute.

Just run the SpringBootMvcApplication class as spring boot application. You should see below output for our endpoints being configured.


2018-05-23 17:02:25.830  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameRS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloRS()
2018-05-23 17:02:25.831  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSSUpdated]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSSUpdated()
2018-05-23 17:02:25.832  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSS()

Spring Bean Request Scope Test

Open any browser and go to URL http://localhost:8080/nameRS and check the console output. You should see DataRequestScope Constructor Called getting printed on each request.

Spring Bean Session Scope Test

Go to http://localhost:8080/nameSS and you would get following output.

Spring Bean Session Scope Test Output

Now go to http://localhost:8080/nameSSUpdated so that DataSessionScope name value is updated to Session Scope Updated.

Spring Bean Scopes test

Now again go to http://localhost:8080/nameSS and you should see the updated value.

spring beans scope

By this time, you should see DataSessionScope Constructor Called at XXX only once in the console output.

Now wait for 1 minute so that our session scoped bean is invalidated. Then again go to http://localhost:8080/nameSS and you should see the original output. Also you should check console message for creation of DataSessionScope again by the container.

spring bean session scope

That’s all for spring beans scope tutorial.

What is thread safety? :: Three ways to make an object thread-safe

What is thread safety?

Thread safety simply means that the fields of an object or class always maintain a valid state, as observed by other objects and classes, even when used concurrently by multiple threads.

One of the first guidelines I proposed in this column (see “Designing object initialization“) is that you should design classes such that objects maintain a valid state, from the beginning of their lifetimes to the end. If you follow this advice and create objects whose instance variables all are private and whose methods only make proper state transitions on those instance variables, you’re in good shape in a single-threaded environment. But you may get into trouble when more threads come along.

Multiple threads can spell trouble for your object because often, while a method is in the process of executing, the state of your object can be temporarily invalid. When just one thread is invoking the object’s methods, only one method at a time will ever be executing, and each method will be allowed to finish before another method is invoked. Thus, in a single-threaded environment, each method will be given a chance to make sure that any temporarily invalid state is changed into a valid state before the method returns.

Once you introduce multiple threads, however, the JVM may interrupt the thread executing one method while the object’s instance variables are still in a temporarily invalid state. The JVM could then give a different thread a chance to execute, and that thread could call a method on the same object. All your hard work to make your instance variables private and your methods perform only valid state transformations will not be enough to prevent this second thread from observing the object in an invalid state.

Such an object would not be thread-safe, because in a multithreaded environment, the object could become corrupted or be observed to have an invalid state. A thread-safe object is one that always maintains a valid state, as observed by other classes and objects, even in a multithreaded environment.

Why worry about thread safety?

There are two big reasons you need to think about thread safety when you design classes and objects in Java:

  1. Support for multiple threads is built into the Java language and API
  2. All threads inside a Java virtual machine (JVM) share the same heap and method area

Because multithreading is built into Java, it is possible that any class you design eventually may be used concurrently by multiple threads. You needn’t (and shouldn’t) make every class you design thread-safe, because thread safety doesn’t come for free. But you should at least think about thread safety every time you design a Java class. You’ll find a discussion of the costs of thread safety and guidelines concerning when to make classes thread-safe later in this article.

Given the architecture of the JVM, you need only be concerned with instance and class variables when you worry about thread safety. Because all threads share the same heap, and the heap is where all instance variables are stored, multiple threads can attempt to use the same object’s instance variables concurrently. Likewise, because all threads share the same method area, and the method area is where all class variables are stored, multiple threads can attempt to use the same class variables concurrently. When you do choose to make a class thread-safe, your goal is to guarantee the integrity — in a multithreaded environment — of instance and class variables declared in that class.

You needn’t worry about multithreaded access to local variables, method parameters, and return values, because these variables reside on the Java stack. In the JVM, each thread is awarded its own Java stack. No thread can see or use any local variables, return values, or parameters belonging to another thread.

Given the structure of the JVM, local variables, method parameters, and return values are inherently “thread-safe.” But instance variables and class variables will only be thread-safe if you design your class appropriately.

RGBColor #1: Ready for a single thread

As an example of a class that is not thread-safe, consider the RGBColor class, shown below. Instances of this class represent a color stored in three private instance variables: rg, and b. Given the class shown below, an RGBColorobject would begin its life in a valid state and would experience only valid-state transitions, from the beginning of its life to the end — but only in a single-threaded environment.

// In file threads/ex1/RGBColor.java
// Instances of this class are NOT thread-safe.
public class RGBColor {
    private int r;
    private int g;
    private int b;
    public RGBColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        this.r = r;
        this.g = g;
        this.b = b;
    }
    public void setColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        this.r = r;
        this.g = g;
        this.b = b;
    }
    /**
    * returns color in an array of three ints: R, G, and B
    */
    public int[] getColor() {
        int[] retVal = new int[3];
        retVal[0] = r;
        retVal[1] = g;
        retVal[2] = b;
        return retVal;
    }
    public void invert() {
        r = 255 - r;
        g = 255 - g;
        b = 255 - b;
    }
    private static void checkRGBVals(int r, int g, int b) {
        if (r < 0 || r > 255 || g < 0 || g > 255 ||
            b < 0 || b > 255) {
            throw new IllegalArgumentException();
        }
    }
}

Because the three instance variables, intrg, and b, are private, the only way other classes and objects can access or influence the values of these variables is via RGBColor‘s constructor and methods. The design of the constructor and methods guarantees that:

  1. RGBColor‘s constructor will always give the variables proper initial values
  2. Methods setColor() and invert() will always perform valid state transformations on these variables
  3. Method getColor() will always return a valid view of these variables

Note that if bad data is passed to the constructor or the setColor() method, they will complete abruptly with an InvalidArgumentException. The checkRGBVals() method, which throws this exception, in effect defines what it means for an RGBColor object to be valid: the values of all three variables, rg, and b, must be between 0 and 255, inclusive. In addition, in order to be valid, the color represented by these variables must be the most recent color either passed to the constructor or setColor() method, or produced by the invert()method.

If, in a single-threaded environment, you invoke setColor() and pass in blue, the RGBColor object will be blue when setColor() returns. If you then invoke getColor() on the same object, you’ll get blue. In a single-threaded society, instances of this RGBColor class are well-behaved.

Throwing a concurrent wrench into the works

Unfortunately, this happy picture of a well-behaved RGBColor object can turn scary when other threads enter the picture. In a multithreaded environment, instances of the RGBColor class defined above are susceptible to two kinds of bad behavior: write/write conflicts and read/write conflicts.

Write/write conflicts

Imagine you have two threads, one thread named “red” and another named “blue.” Both threads are trying to set the color of the same RGBColor object: The red thread is trying to set the color to red; the blue thread is trying to set the color to blue.

Both of these threads are trying to write to the same object’s instance variables concurrently. If the thread scheduler interleaves these two threads in just the right way, the two threads will inadvertently interfere with each other, yielding a write/write conflict. In the process, the two threads will corrupt the object’s state.

The Unsynchronized RGBColor applet

The following applet, named Unsynchronized RGBColor, demonstrates one sequence of events that could result in a corrupt RGBColor object. The red thread is innocently trying to set the color to red while the blue thread is innocently trying to set the color to blue. In the end, the RGBColor object represents neither red nor blue but the unsettling color, magenta.

For some reason, your browser won’t let you see this way cool Java applet.To step through the sequence of events that lead to a corrupted RGBColorobject, press the applet’s Step button. Press Back to back up a step, and Reset to back up to the beginning. As you go, a line of text at the bottom of the applet will explain what’s happening during each step.

For those of you who can’t run the applet, here’s a table that shows the sequence of events demonstrated by the applet:

Thread Statement r g b Color
none object represents green 0 255 0
blue blue thread invokes setColor(0, 0, 255) 0 255 0
blue checkRGBVals(0, 0, 255); 0 255 0
blue this.r = 0; 0 255 0
blue this.g = 0; 0 255 0
blue blue gets preempted 0 0 0
red red thread invokes setColor(255, 0, 0) 0 0 0
red checkRGBVals(255, 0, 0); 0 0 0
red this.r = 255; 0 0 0
red this.g = 0; 255 0 0
red this.b = 0; 255 0 0
red red thread returns 255 0 0
blue later, blue thread continues 255 0 0
blue this.b = 255 255 0 0
blue blue thread returns 255 0 255
none object represents magenta 255 0 255

As you can see from this applet and table, the RGBColor is corrupted because the thread scheduler interrupts the blue thread while the object is still in a temporarily invalid state. When the red thread comes in and paints the object red, the blue thread is only partially finished painting the object blue. When the blue thread returns to finish the job, it inadvertently corrupts the object.

Read/write conflicts

Another kind of misbehavior that may be exhibited in a multithreaded environment by instances of this RGBColor class is read/write conflicts. This kind of conflict arises when an object’s state is read and used while in a temporarily invalid state due to the unfinished work of another thread.

For example, note that during the blue thread’s execution of the setColor()method above, the object at one point finds itself in the temporarily invalid state of black. Here, black is a temporarily invalid state because:

  1. It is temporary: Eventually, the blue thread intends to set the color to blue.
  2. It is invalid: No one asked for a black RGBColor object. The blue thread is supposed to turn a green object into blue.

If the blue thread is preempted at the moment the object represents black by a thread that invokes getColor() on the same object, that second thread would observe the RGBColor object’s value to be black.

Here’s a table that shows a sequence of events that could lead to just such a read/write conflict:

Thread Statement r g b Color
none object represents green 0 255 0
blue blue thread invokes setColor(0, 0, 255) 0 255 0
blue checkRGBVals(0, 0, 255); 0 255 0
blue this.r = 0; 0 255 0
blue this.g = 0; 0 255 0
blue blue gets preempted 0 0 0
red red thread invokes getColor() 0 0 0
red int[] retVal = new int[3]; 0 0 0
red retVal[0] = 0; 0 0 0
red retVal[1] = 0; 0 0 0
red retVal[2] = 0; 0 0 0
red return retVal; 0 0 0
red red thread returns black 0 0 0
blue later, blue thread continues 0 0 0
blue this.b = 255 0 0 0
blue blue thread returns 0 0 255
none object represents blue 0 0 255

As you can see from this table, the trouble begins when the blue thread is interrupted when it has only partially finished painting the object blue. At this point the object is in a temporarily invalid state of black, which is exactly what the red thread sees when it invokes getColor() on the object.

Three ways to make an object thread-safe

There are basically three approaches you can take to make an object such as RGBThread thread-safe:

  1. Synchronize critical sections
  2. Make it immutable
  3. Use a thread-safe wrapper

Approach 1: Synchronizing the critical sections

The most straightforward way to correct the unruly behavior exhibited by objects such as RGBColor when placed in a multithreaded context is to synchronize the object’s critical sections. An object’s critical sections are those methods or blocks of code within methods that must be executed by only one thread at a time. Put another way, a critical section is a method or block of code that must be executed atomically, as a single, indivisible operation. By using Java’s synchronized keyword, you can guarantee that only one thread at a time will ever execute the object’s critical sections.

To take this approach to making your object thread-safe, you must follow two steps: you must make all relevant fields private, and you must identify and synchronize all the critical sections.

Step 1: Make fields private

Synchronization means that only one thread at a time will be able to execute a bit of code (a critical section). So even though it’s fields you want to coordinate access to among multiple threads, Java’s mechanism to do so actually coordinates access to code. This means that only if you make the data private will you be able to control access to that data by controlling access to the code that manipulates the data.

The first rule to follow when making a class thread-safe through synchronizing its critical sections, therefore, is to make its fields private. Any field that you need to coordinate multithreaded access to must be private, otherwise it may be possible for other classes and objects to ignore your critical sections and access the fields directly.

Not every field must be private — only those that will be involved in any temporarily invalid states created by the object’s or class’s critical sections. For example, constants (static final variables) can’t be corrupted by multiple threads, so they needn’t be private.

Step 2: Identify and synchronize critical sections

Once you’ve made the appropriate variables private, you need only mark the object’s critical sections as synchronized. As mentioned above, a critical sectionis a bit of code that must be executed atomically, that is, as a single, indivisible operation. For example, the statements:

this.r = r;
this.g = g;
this.b = b;

must operate atomically for the setColor() method to behave as expected in a multithreaded environment. To ensure proper behavior, these three statements need to appear as if they were executed by a single, indivisible JVM instruction.

Note that reads and writes of primitive types and object references are atomic by definition, except for longs and doubles. This means that if you have an int, for example, that is independent of any other fields in an object, you needn’t synchronize code that accesses that field. If two threads were to attempt to write two different values to the int concurrently, the resulting value would be one or the other. The int would never end up with a corrupted value made up of some bits written by one thread and other bits written by the other thread.

The same is not necessarily true, however, for longs and doubles. If two different threads were to attempt to write two different values to a longconcurrently, you might just end up with a corrupted value consisting of some bits written by one thread and other bits written by the other thread. Multithreaded access to longs and doubles, therefore, should always be synchronized.

RGBColor # 2: Thread safety through synchronization

Here’s a revised version of the RGBColor() class. This version, which has its critical sections marked as synchronized, is thread-safe:

// In file threads/ex2/RGBColor.java
// Instances of this class are thread-safe.
public class RGBColor {
    private int r;
    private int g;
    private int b;
    public RGBColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        this.r = r;
        this.g = g;
        this.b = b;
    }
    public void setColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        synchronized (this) {
            this.r = r;
            this.g = g;
            this.b = b;
        }
    }
    /**
    * returns color in an array of three ints: R, G, and B
    */
    public int[] getColor() {
        int[] retVal = new int[3];
        synchronized (this) {
            retVal[0] = r;
            retVal[1] = g;
            retVal[2] = b;
        }
        return retVal;
    }
    public synchronized void invert() {
        r = 255 - r;
        g = 255 - g;
        b = 255 - b;
    }
    private static void checkRGBVals(int r, int g, int b) {
        if (r < 0 || r > 255 || g < 0 || g > 255 ||
            b < 0 || b > 255) {
            throw new IllegalArgumentException();
        }
    }
}

The Synchronized RGBColor applet

The following applet, named Synchronized RGBColor, demonstrates a similar sequence of events to the one that led to a corrupt RGBColor object in the previous demonstration applet. This applet, however, shows how the thread-safe version of RGBColor is able to maintain a valid state, even when multiple threads are attempting to write to the object. As before, a red thread is trying to set the color to red while a blue thread is trying to set the color to blue. In the end, this RGBColor object represents not the invalid color magenta, but the valid — and satisfying — color red.

For some reason, your browser won’t let you see this way-cool Java applet.

To step through the sequence of events that led to a corrupted RGBColor object, press the applet’s Step button. Press Back to back up a step, and Reset to back up to the beginning. As you go, a line of text at the bottom of the applet will explain what’s happening during each step.

For those of you who can’t run the applet, here’s a table that shows the sequence of events demonstrated by the applet:

Thread Statement r g b Color
none object represents green 0 255 0
blue blue thread invokes setColor(0, 0, 255) 0 255 0
blue blue thread acquires lock 0 255 0
blue checkRGBVals(0, 0, 255); 0 255 0
blue this.r = 0; 0 255 0
blue this.g = 0; 0 255 0
blue blue gets preempted 0 0 0
red red thread invokes setColor(255, 0, 0) 0 0 0
red red thread blocks because object locked 0 0 0
blue later, blue thread continues 0 0 0
blue this.b = 255 0 0 0
blue blue thread returns and releases lock 0 0 255
red later, red thread acquires lock and continues 0 0 255
red checkRGBVals(255, 0, 0); 0 0 255
red this.r = 255; 0 0 255
red this.g = 0; 255 0 255
red this.b = 0; 255 0 255
red red thread returns and releases lock 255 0 0
none object represents red 255 0 0

Note that this version of RGBColor still has temporarily invalid states from time to time. To be specific, at times during the sequence shown above this object’s state does represent the invalid states black and magenta. The trick to synchronization is that while an object is having one of those temporarily invalid moments, no other classes or objects are allowed to use or observe the state of the object via other threads.

Approach 2: Immutable objects

An alternative way to make an object thread-safe is to make the object immutable. An immutable object is one whose state can’t be changed once the object is created.

Immutable objects are, by their very nature, thread-safe simply because threads have to be able to write to an object’s instance variables to experience a read/write or write/write conflict. Because no methods (only the constructor) of an immutable object actually write to the object’s instance variables, the object is by definition thread-safe.

In this approach to making an object thread-safe, you don’t mark critical sections as synchronized. Instead, you separate out the critical sections that read instance variables from those that write to instance variables. The critical sections that read are left as-is. The critical sections that write must be changed so that, instead of altering the current object’s instance variables, they create a new object that embodies the new state and returns a reference to that object.

RGBColor # 3: Thread safety through immutability

Here’s an immutable version of RGBColor:

// In file threads/ex3/RGBColor.java
// Instances of this immutable class
// are thread-safe.
public class RGBColor {
    private final int r;
    private final int g;
    private final int b;
    public RGBColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        this.r = r;
        this.g = g;
        this.b = b;
    }
    /**
    * returns color in an array of three ints: R, G, and B
    */
    public int[] getColor() {
        int[] retVal = new int[3];
        retVal[0] = r;
        retVal[1] = g;
        retVal[2] = b;
        return retVal;
    }
    public RGBColor invert() {
        RGBColor retVal = new RGBColor(255 - r,
            255 - g, 255 - b);
        return retVal;
    }
    private static void checkRGBVals(int r, int g, int b) {
        if (r < 0 || r > 255 || g < 0 || g > 255 ||
            b < 0 || b > 255) {
            throw new IllegalArgumentException();
        }
    }
}

Note that the setColor() method is simply removed, as it doesn’t make sense in an immutable RGBColor object. The getColor() method, which reads the instance variables, is identical to what it has been, except now it doesn’t have to be synchronized. The invert() method, which writes to the instance variables, is changed. Instead of inverting the current object’s color, this new invert()creates a new RGBColor object that represents the inverse of the object upon which invert() is invoked, and returns a reference to that object.

Approach 3: Thread-safe wrappers

The third approach to making an object thread-safe is to embed that object in a thread-safe wrapper object. In this approach you leave the original class (which isn’t thread-safe) unchanged and create a separate class that is thread-safe. Instances of the new class serve as thread-safe “front ends” to instances of the original class.

SafeRGBColor: A thread-safe wrapper

Here’s an example of this approach applied to the very first version of RGBColorpresented in this article.

// In file threads/ex1/SafeRGBColor.java
// Instances of this class are thread-safe
// wrappers of RGBColor objects, which are
// not thread-safe.
public class SafeRGBColor {
    private RGBColor color;
    public SafeRGBColor(int r, int g, int b) {
        color = new RGBColor(r, g, b);
    }
    public synchronized void setColor(int r, int g, int b) {
        color.setColor(r, g, b);
    }
    /**
    * returns color in an array of three ints: R, G, and B
    */
    public synchronized int[] getColor() {
        return color.getColor();
    }
    public synchronized void invert() {
        color.invert();
    }
}

Why not just synchronize everything?

As mentioned earlier in this article, you don’t want to make every class you design thread-safe — only classes whose instances will be used concurrently by multiple threads. The reason you don’t want to make every class thread-safe is that thread safety may involve a performance penalty. For example:

  • Synchronized method invocations generally are going to be slower than non-synchronized method invocations. In Sun’s current JVM, for example, synchronized method invocations are 4 to 6 times slower than non-synchronized method invocations. In the future, the speed of synchronized method invocations should improve, but they will likely never achieve parity with non-synchronized method invocations.
  • Unnecessary synchronized method invocations (and synchronized blocks) can cause unnecessary blocking and unblocking of threads, which can hurt performance.
  • Immutable objects tend to be instantiated more often, leading to greater numbers of often short-lived objects that can increase the work of the garbage collector.
  • Synchronization gives rise to the possibility of deadlock, a severe performance problem in which your program appears to hang.

None of these performance setbacks are good excuses for neglecting to make classes that need to thread-safe so, but they do constitute good reasons not to make classes thread-safe unnecessarily.

Pros and cons of the three approaches to thread safety

Synchronizing critical sections

Marking your code’s critical sections as synchronized is the “normal” approach to making classes synchronized. It is also the only way to use wait() and notify() to get threads to cooperate towards achieving some common goal. So the guideline concerning Approach 1 is simply:

Unless special circumstances make it appropriate to use an immutable or wrapper object, use Approach 1 to make your class thread-safe: Make sure the appropriate instance variables are private and mark the critical sections as synchronized.

Using immutable objects

Achieving thread safety by making objects immutable (Approach 2) works well when objects are small and represent values of a simple abstract data type. The Java API includes several examples of immutable objects, including String and the primitive type wrappers such as IntegerLongFloatBooleanCharacter, and so on.

It’s worth noting that instances of the AWT’s Color class are immutable. Likewise, the immutable approach may make sense for this article’s RGBColorclass, which is similar in functionality to the AWT’s Color class, because RGBColor objects are small (they contain only 3 ints) and conceptually represent values of a simple abstract data type.

Another benefit of immutable objects is that you can pass references to them to methods without worrying that the method will change the object’s state. In addition, if the overhead of immutability (excessive creation of short-lived objects) may at times be too inefficient, you can also define a mutable companion class that can be used when the immutable version isn’t appropriate. An example of this design approach in the Java API is the StringBuffer class, which serves as a mutable companion to the immutable String class. Note that the StringBuffer class is also thread-safe, but it uses the “normal” approach: its instance variables are private and its critical sections are synchronized.

Using wrapper objects

The wrapper object approach to thread safety (Approach 3) makes the most sense when you want to give clients a choice between a version of a class that is thread-safe and one that isn’t. This approach also makes sense when you’re a client of someone else’s class that isn’t thread-safe, but you need to use the class in a multithreaded environment. Once you define your own thread-safe wrapper for the class, you can safely use the class in a multithreaded environment by going through your wrapper.

A good example of this approach from the Java API comes from the 1.2 collections library. The 1.2 collections library defines a hierarchy that includes classes that represent many kinds of collections — none of which are thread-safe. But class Collection includes several class methods that will enclose a regular collection object in a thread-safe wrapper, so you can safely use the object in a multithreaded context. This design gives users of the collections library a choice of using a collections object that is thread-safe and one that isn’t.

Note that a common attribute of wrapper classes like those you would use to add thread safety to the enclosed object is that the wrapper accepts the same messages as the enclosed object. In other words, often a wrapper class will descend from a common superclass or superinterface with the enclosed class. (For those of you familiar with the Design Patterns book by Gamma, et. al., this is the “decorator” pattern. See Resources for more information on this book.) This decorator design approach to wrappers, which is exhibited by the thread-safe wrappers of the 1.2 collections library, allows the thread safety to be dynamically added or removed from an object.

The advantage of the approach to wrapping taken by SafeRGBColor in this article is that thread safety is guaranteed when using a SafeRGBColor object, because the enclosed RGBColor object is created by SafeRGBColor‘s constructor and never returned by its own methods or passed to another object’s methods. The decorator design approach, because the enclosed object is instantiated by the client and passed to the constructor of the thread-safe wrapper, requires that clients create the enclosed objects themselves first. Thus, to achieve thread safety, the decorator approach requires that clients have the discipline not to use the enclosed object except through the thread-safe wrapper.

When to make classes thread-safe

When you are designing the classes that compose a Java applet or application, your thread-safety decision should be based simply on whether or not each class will be exposed to potential write/write or read/write conflicts by your programs. To know whether or not such conflicts are possible, you just have to know how your program will work.

For example, I didn’t choose thread safety for any of the classes that compose the two simulation applets included above in this article, because they won’t be exposed to multiple threads. Once the init() method of the applet has returned, the only thread that will be coursing through the veins of this code is the GUI event handler thread — and there is only one GUI event handler thread. As a result, even if a user frantically clicks the Reset button as quickly as possible after the Step button, the code of my applet will handle the Step button press completely before beginning to handle the Reset button press.

By contrast, I did make thread-safe certain classes that compose the JVM Simulation applets that are delivered on the CD-ROM of my JVM book (see Resources). These applets have Run and Stop buttons as well as Step and Reset buttons. When the user clicks Run, I fire off a thread that animates the applet, making the applet run as if the user were clicking Step about twice a second. When the user clicks Stop, the even handler thread comes in to stop the animation thread but mustn’t be allowed to do so before the run thread completes its current step and puts the JVM simulator into a valid state.

If, instead of creating classes for an applet or application, you are creating classes for a library, either one that will be shared in-house or will serve as a product in its own right, you have a different problem. You may not know exactly how the classes will be used. In such cases, it may be a good idea to give clients a choice via the thread-safe wrapper approach.

Conclusion

The most important point to take away from this article is that when programming in Java, you should at least think about thread safety every time you design a class.

Here’s a collection of the exception guidelines put forth by this article:

  • Given that thread safety can have a performance cost, don’t make every class thread-safe — only those classes that will actually be used concurrently by multiple threads
  • Don’t avoid making classes thread-safe that need to be thread-safe out of fear of a performance impact
  • When making an object thread-safe via Approach 1, synchronize only the critical sections of the class
  • Use an immutable object especially if the object is small or represents a fundamental data type
  • If you can’t change a non-thread-safe class, use a wrapper object
  • If you are creating a library of classes that will be used in both thread-safe and non-thread-safe requirements, consider making wrappers an option

A brief overview of the Fork/Join Framework in Java

Introduction

The Fork/Join framework is a framework to solve a problem using a concurrent divide-and-conquer approach. They were introduced to complement the existing concurrency API. Before their introduction, the existing ExecutorService implementations were the popular choice to run asynchronous tasks, but they work best when the tasks are homogenous and independent. Running dependent tasks and combining their results using those implementations were not easy. With the introduction of the Fork/Join framework, an attempt was made to address this shortcoming. In this post, we will take a brief look at the API and solve a couple of simple problems to understand how they work.

Solving a non-blocking task

Let’s jump directly into code. Let’s create a task which would return the sum of all elements of a List. The following steps represent our algorithm in pseudo-code:

01. Find the middle index of the list

02. Divide the list in the middle

03. Recursively create a new task which will compute the sum of the left part

04. Recursively create a new task which will compute the sum of the right part

05. Add the result of the left sum, the middle element, and the right sum

Here is the code –

01 @Slf4j
02 public class ListSummer extends RecursiveTask<Integer> {
03   private final List<Integer> listToSum;
04
05   ListSummer(List<Integer> listToSum) {
06     this.listToSum = listToSum;
07   }
08
09   @Override
10   protected Integer compute() {
11     if (listToSum.isEmpty()) {
12       log.info("Found empty list, sum is 0");
13       return 0;
14     }
15
16     int middleIndex = listToSum.size() / 2;
17     log.info("List {}, middle Index: {}", listToSum, middleIndex);
18
19     List<Integer> leftSublist = listToSum.subList(0, middleIndex);
20     List<Integer> rightSublist = listToSum.subList(middleIndex + 1, listToSum.size());
21
22     ListSummer leftSummer = new ListSummer(leftSublist);
23     ListSummer rightSummer = new ListSummer(rightSublist);
24
25     leftSummer.fork();
26     rightSummer.fork();
27
28     Integer leftSum = leftSummer.join();
29     Integer rightSum = rightSummer.join();
30     int total = leftSum + listToSum.get(middleIndex) + rightSum;
31     log.info("Left sum is {}, right sum is {}, total is {}", leftSum, rightSum, total);
32
33     return total;
34   }
35 }

Firstly, we extend the RecursiveTask subtype of the ForkJoinTask. This is the type to extend from when we expect our concurrent task to return a result. When a task does not return a result but only perform an effect, we extend the RecursiveAction subtype. For most of the practical tasks that we solve, these two subtypes are sufficient.

Secondly, both RecursiveTask and RecursiveAction define an abstract compute method. This is where we put our computation.

Thirdly, inside our compute method, we check the size of the list that is passed through the constructor. If it is empty, we already know the result of the sum which is zero, and we return immediately. Otherwise, we divide our lists into two sublists and create two instances of our ListSummer type. We then call the fork() method (defined in ForkJoinTask) on these two instances –

1 leftSummer.fork();
2 rightSummer.fork();

Which cause these tasks to be scheduled for asynchronous execution, the exact mechanism which is used for this purpose will be explained later in this post.

After that, we invoke the join() method (also defined in ForkJoinTask) to wait for the result of these two parts

1 Integer leftSum = leftSummer.join();
2 Integer rightSum = rightSummer.join();

Which are then summed with the middle element of the list to get the final result.

Plenty of log messages have been added to make the example easier to understand. However, when we process a list containing thousands of entries, it might not be a good idea to have this detailed logging, especially logging the entire list.

That’s pretty much it. Let’s create a test class now for a test run –

01 public class ListSummerTest {
02
03   @Test
04   public void shouldSumEmptyList() {
05     ListSummer summer = new ListSummer(List.of());
06     ForkJoinPool forkJoinPool = new ForkJoinPool();
07     forkJoinPool.submit(summer);
08
09     int result = summer.join();
10
11     assertThat(result).isZero();
12   }
13
14   @Test
15   public void shouldSumListWithOneElement() {
16     ListSummer summer = new ListSummer(List.of(5));
17     ForkJoinPool forkJoinPool = new ForkJoinPool();
18     forkJoinPool.submit(summer);
19
20     int result = summer.join();
21
22     assertThat(result).isEqualTo(5);
23   }
24
25   @Test
26   public void shouldSumListWithMultipleElements() {
27     ListSummer summer = new ListSummer(List.of(
28         123456789
29     ));
30     ForkJoinPool forkJoinPool = new ForkJoinPool();
31     forkJoinPool.submit(summer);
32
33     int result = summer.join();
34
35     assertThat(result).isEqualTo(45);
36   }
37 }

In the test, we create an instance of the ForkJoinPool. A ForkJoinPool is a unique ExecutorService implementation for running ForkJoinTasks. It employs a special algorithm known as the work-stealing algorithm. Contrary to the other ExecutorService implementations where there is only a single queue holding all the tasks to be executed, in a work-stealing implementation, each worker thread gets its work queue. Each thread starts executing tasks from their queue.

When we detect that a ForkJoinTask can be broken down into multiple smaller subtasks, we do break them into smaller tasks, and then we invoke the fork() method on those tasks. This invocation causes the subtasks to be pushed into the executing thread’s queue. During the execution, when one thread exhausts its queue/has no tasks to execute, it can “steal” tasks from other thread’s queue (hence the name “work-stealing”). This stealing behaviour is what results in a better throughput than using any other ExecutorService implementations.

Earlier, when we invoked fork() on our leftSummer and rightSummer task instances, they got pushed into the work queue of the executing thread, after which they were “stolen” by other active threads in the pool (and so on) since they did not have anything else to do at that point.

Pretty cool, right?

Solving a blocking task

The problem we solved just now is non-blocking in nature. If we want to solve a problem which does some blocking operation, then to have a better throughput we will need to change our strategy.

Let’s examine this with another example. Let’s say we want to create a very simple web crawler. This crawler will receive a list of HTTP links, execute GET requests to fetch the response bodies, and then calculate the response length. Here is the code –

01 @Slf4j
02 public class ResponseLengthCalculator extends RecursiveTask<Map<String, Integer>> {
03   private final List<String> links;
04
05   ResponseLengthCalculator(List<String> links) {
06     this.links = links;
07   }
08
09   @Override
10   protected Map<String, Integer> compute() {
11     if (links.isEmpty()) {
12       log.info("No more links to fetch");
13       return Collections.emptyMap();
14     }
15
16     int middle = links.size() / 2;
17     log.info("Middle index: {}", links, middle);
18     ResponseLengthCalculator leftPartition = new ResponseLengthCalculator(links.subList(0, middle));
19     ResponseLengthCalculator rightPartition = newResponseLengthCalculator(links.subList(middle + 1, links.size()));
20
21     log.info("Forking left partition");
22     leftPartition.fork();
23     log.info("Left partition forked, now forking right partition");
24     rightPartition.fork();
25     log.info("Right partition forked");
26
27     String middleLink = links.get(middle);
28     HttpRequester httpRequester = new HttpRequester(middleLink);
29     String response;
30     try {
31       log.info("Calling managedBlock for {}", middleLink);
32       ForkJoinPool.managedBlock(httpRequester);
33       response = httpRequester.response;
34     catch (InterruptedException ex) {
35       log.error("Error occurred while trying to implement blocking link fetcher", ex);
36       response = "";
37     }
38
39     Map<String, Integer> responseMap = new HashMap<>(links.size());
40
41     Map<String, Integer> leftLinks = leftPartition.join();
42     responseMap.putAll(leftLinks);
43     responseMap.put(middleLink, response.length());
44     Map<String, Integer> rightLinks = rightPartition.join();
45     responseMap.putAll(rightLinks);
46
47     log.info("Left map {}, middle length {}, right map {}", leftLinks, response.length(), rightLinks);
48
49     return responseMap;
50   }
51
52   private static class HttpRequester implements ForkJoinPool.ManagedBlocker {
53     private final String link;
54     private String response;
55
56     private HttpRequester(String link) {
57       this.link = link;
58     }
59
60     @Override
61     public boolean block() {
62       HttpGet headRequest = new HttpGet(link);
63       CloseableHttpClient client = HttpClientBuilder
64           .create()
65           .disableRedirectHandling()
66           .build();
67       try {
68         log.info("Executing blocking request for {}", link);
69         CloseableHttpResponse response = client.execute(headRequest);
70         log.info("HTTP request for link {} has been executed", link);
71         this.response = EntityUtils.toString(response.getEntity());
72       catch (IOException e) {
73         log.error("Error while trying to fetch response from link {}: {}", link, e.getMessage());
74         this.response = "";
75       }
76       return true;
77     }
78
79     @Override
80     public boolean isReleasable() {
81       return false;
82     }
83   }
84 }

We create an implementation of the ForkJoinPool.ManagedBlocker where we put the blocking HTTP call. This interface defines two methods – block() and isReleasable(). The block() method is where we put our blocking call. After we are done with our blocking operation, we return true indicating that no further blocking is necessary. We return false from the isReleasable() implementation to indicate to a fork-join worker thread that the block() method implementation is potentially blocking in nature. The isReleasable() implementation will be invoked by a fork-join worker thread first before it invokes the block() method. Finally, we submit our  HttpRequester instance to our pool by invoking ForkJoinPool.managedBlock()static method. After that our blocking task will start executing. When it blocks on the HTTP request, the ForkJoinPool.managedBlock() method will also arrange for a spare thread to be activated if necessary to ensure sufficient parallelism.

Let’s take this implementation for a test drive then! Here’s the code –

01 public class ResponseLengthCalculatorTest {
02
03   @Test
04   public void shouldReturnEmptyMapForEmptyList() {
05     ResponseLengthCalculator responseLengthCalculator = newResponseLengthCalculator(Collections.emptyList());
06     ForkJoinPool pool = new ForkJoinPool();
07
08     pool.submit(responseLengthCalculator);
09
10     Map<String, Integer> result = responseLengthCalculator.join();
11     assertThat(result).isEmpty();
12   }
13
14   @Test
15   public void shouldHandle200Ok() {
16     ResponseLengthCalculator responseLengthCalculator = newResponseLengthCalculator(List.of(
17         "http://httpstat.us/200"
18     ));
19     ForkJoinPool pool = new ForkJoinPool();
20
21     pool.submit(responseLengthCalculator);
22
23     Map<String, Integer> result = responseLengthCalculator.join();
24     assertThat(result)
25         .hasSize(1)
26         .containsKeys("http://httpstat.us/200")
27         .containsValue(0);
28   }
29
30   @Test
31   public void shouldFetchResponseForDifferentResponseStatus() {
32     ResponseLengthCalculator responseLengthCalculator = newResponseLengthCalculator(List.of(
33         "http://httpstat.us/200",
34         "http://httpstat.us/302",
35         "http://httpstat.us/404",
36         "http://httpstat.us/502"
37     ));
38     ForkJoinPool pool = new ForkJoinPool();
39
40     pool.submit(responseLengthCalculator);
41
42     Map<String, Integer> result = responseLengthCalculator.join();
43     assertThat(result)
44         .hasSize(4);
45   }
46 }

That’s it for today, folks! As always, any feedback/improvement suggestions/comments are highly appreciated!

All the examples discussed here can be found onGithub (specific commit).

A big shout out to the awesome http://httpstat.us service, it was quite helpful for developing the simple tests.