preface

Concurrent programming in order to make the program run faster, improve the response speed of the program, although we hope that through multi-threaded tasks let the program run faster, but also a lot of challenges, such as security like threads, thread context switching problem, the hardware and software resource constraints and other issues, these are concurrent programming brings us problems. Thread safety is one of the most important issues we care about, and we are going to focus on thread safety.

Thread safety

First of all, we need to understand how to define thread safety and thread insecurity. I did a lot of research and couldn’t come up with a definition that I think is authoritative and rigorous, but I think there is one concept that can help us distinguish thread safety from unsafe: races.

So what is a race relationship? When multiple threads access the same resource at the same time, if the Shared resource is sensitive to access sequence, the output of the program results will depend heavily on the sequence of the deadly dependency, this time is a race relation between multiple threads, when there is a race relationship, program execution results at this time there are a lot of uncertainty, that is the result of the program is run by sheer luck.

Is a thread that has race relations necessarily unsafe and a thread that does not have race relations necessarily safe? In the absence of any other constraints, there are races between threads without adding additional synchronization, and that is definitely not thread-safe; If there are no races, they must be thread-safe. Because races occur on shared resources, the absence of races means that shared resources are not accessed at the same time, and there is no thread-safety issue.

Thread safety is defined in the book Java Concurrent Programming in Action: when multiple threads access a class, the class behaves correctly, regardless of how the runtime is scheduled or how the threads are executed interchangeably, and without any additional synchronization or collaboration in the main code. And the book begins its first chapter by saying that the core of writing thread-safe code is to do rightManagement of operation access. In order to prevent the shared state from being uncontrollable during concurrent access, we must pay special attention to the shared state in the thread.

Tips:

Shared and mutable state this is important to keep in mind, this is at the heart of thread safety

Java inter-thread messaging

In imperative programming, there are two communication mechanisms between threads: shared memory and messaging.

  • Shared memory: The shared memory model is the most widely used model. In this communication model, a shared variable is set and the communication between multiple threads is achieved by operating the same variable. But this approach requires us to explicitly specify mutually exclusive execution between threads where we operate on shared variables or in code snippets.
  • Messaging: In the concurrency model of messaging, there is no common state between threads, and threads must communicate explicitly by explicitly sending messages.

Multithreading communication through the Shared memory is the most, in Java multi-thread communication mode is using Shared memory, but there are disadvantages this way, this way of communication is between threads in memory by writing – read public state to communicate implicitly, how is the public state between the multithreaded memory read and write, We can’t see it explicitly, so we need to understand how multiple threads read and write to memory.

Java multithreaded memory interaction

The Java memory model specifies that all variables are stored in main memory and that each thread has its own working memory. Thread’s working memory holds the main memory of the variables of the thread used in the copy of a copy of the thread to Shared variables all the operations must be done in working memory, no direct operation of main memory variables, but variable copy to local memory, in local memory operation has been completed, then the synchronous back into main memory, Different threads cannot directly access variables in each other’s working memory. As shown below:

221.png

When thread A needs to send messages to thread B, thread A copies variables in the main memory to its local memory and processes them in the local memory. After the processing is complete, the data in its local memory is synchronized to the main memory. Thread B synchronizes thread A’s variables into main memory and copies them to its own local thread, and so on and so forth, thread A and thread B complete the message delivery.

In this article, I mainly want to talk about how the message passing between multiple threads through shared memory, and the interaction between multiple threads and shared variables. The Java memory model is an important part of concurrent programming, but I won’t burden you with what it is. I’ll cover it in detail in the next article.

Problems with concurrency

From the introduction above, we may have seen the way multithreading communicates, but this approach also introduces two problems: visibility and access issues.

Since threads exchange data by accessing main memory, if thread A reads some shared data first and thread B modiizes it later, thread A may not see thread B’s changes to the data.

When thread A and thread B make changes to the shared data at the same time, whether it is thread A’s data or thread B’s data.

In addition, there are atomicity and reordering problems, which we will cover in more detail in a later article.

Absolutely thread-safe

As we said earlier, thread safety is related to mutable shared variables, so if there are no shared variables or shared variables are immutable, is this class absolutely thread safe? The answer is yes. These are also what we call immutable and stateless objects, which must be thread-safe.

Stateless object

A stateless object that contains neither any fields nor any references to fields in other classes. The temporary state of a calculation is stored only on the thread stack and can only be accessed by the current thread. Stateless variables can be considered thread-safe because they have no shared state. A Servlet object in Java is a stateless object.

public class ServletTest implements Servlet {

public void init(ServletConfig servletConfig) throws ServletException {}



public ServletConfig getServletConfig(a) {return null; }



public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {}



public String getServletInfo(a) { return null; }



public void destroy(a) {}

}



Copy the code

Immutable object

An immutable object has only one state, and that state is controlled by the constructor. Once an immutable object has been created, there is no way to change it. Since it has only one state, there is no possibility of change, so immutable objects must be thread-safe. But immutable objects, not all fields are declared as final, they are immutable.

An object is immutable if:

  • After an object is created, its state cannot be changed
  • All fields of the object are of final type.
  • The object is created correctly. Because the object you get in multiple threads may not be a fully constructed object.

conclusion

After reading the above, we probably have a general idea of concurrent programming.

  1. The problem of multithreading safety in concurrent programming is related to shared mutable state
  2. Multithreaded communication in Java is carried out through shared memory.
  3. Stateless, immutable objects must be thread-safe.
  4. Atomicity, visibility, reordering problems with concurrent programming

Reference:

Java Concurrent Programming