Interviewer: Do you know what the Java memory model is?

The basic concept

Concurrent, parallel

To quote the highest praise on Zhihu:

You’re in the middle of a meal when the phone comes and you don’t answer it until after you’ve finished, which means you don’t support concurrency or parallelism.

You’re in the middle of a meal when the phone call comes, you stop to answer the phone, and then continue eating, which means you support concurrency.

You’re in the middle of a meal when the phone call comes and you’re eating while you’re talking, which means you support parallelism.

The key to concurrency is that you have the ability to handle multiple tasks, not necessarily all at once. The key to parallelism is your ability to handle multiple tasks at once.

Concurrency: A task-processing mechanism in which the system can process multiple tasks but only one at a time

Parallelism: The system can handle multiple tasks and multiple task processing mechanisms at the same time

High concurrency: A task processing mechanism in which the system can process many requests in parallel at the same time

Concurrent basis

This PDF covers the basics of Java threading, which you can skip if you’re familiar with it

Java memory model

Main memory: All variables are stored in main memory. Working memory: A separate memory for each thread that holds a main memory copy of variables used by the thread.

Each thread has its own shared copy of local memory. If thread A wants to update main memory and let thread B get the updated variable, it needs to:

  1. Update shared variables in local memory A
  2. Flush the updated shared variable to main memory
  3. Thread B updates the latest shared variable from main memory

If threads A and B process A shared variable at the same time, double counting or data conflicts may occur.

Perform optimization out of order

In hardware architecture, an out-of-order optimization of a processor to speed up processing. It is executed by sending multiple instructions out of sequence to different circuit units to achieve greater CPU utilization.

This problem does not occur on a single CPU, but may occur when multiple cpus access the same memory block, as shown below.

example


public class PossibleReordering { private static int x = 0, y = 0; private static int a = 0, b = 0; public static void main(String[] args) throws InterruptedException { int i = 0; for (; ;) { i++; x = 0; y = 0; a = 0; b = 0; Thread one = new Thread(() -> {Thread one = new Thread() -> {Thread one = new Thread() -> { ShortWait (50000); shortWait(50000); a = 1; x = b; }); Thread other = new Thread(() -> { b = 1; y = a; }); one.start(); other.start(); one.join(); other.join(); String result = "first" + I + "time (" + x +", "+ y +") "; if (x == 0 && y == 0) { System.err.println(result); break; } else { System.out.println(result); } } } public static void shortWait(long interval) { long start = System.nanoTime(); long end; do { end = System.nanoTime(); } while (start + interval >= end); }}Copy the code

It is easy to imagine that the result of this code could be (1,0), (0,1), or (1,1), because thread one could finish executing before thread two starts, or vice versa, or even if the instructions are executed simultaneously or alternately.

However, the result of this code execution could also be (0,0). Code instructions may not be executed strictly in the order of code statements. The assignment operations of a=1 and x=b may have been reversed, or the order “reordering” has occurred. (The fact that this result is printed does not necessarily mean that instruction reordering has occurred, as memory visibility issues can also cause this output.)

In addition to the processor, the JIT compiler in a common Java runtime environment also does instruction reordering, where the machine instructions are generated out of order with the bytecode instructions.

The memory barrier

The solution to this problem is to add memory barriers that make all shared variables volatile.

Memory barriers prevent reordering of subsequent instructions and keep variables visible. Readers are strongly advised to do it themselves to deepen understanding.

Pros and cons of concurrency

Advantages:

  1. Speed: Faster response when processing multiple requests simultaneously
  2. Design: Programming has more options and may be simpler, such as file set reading and processing, a single thread needs to write a loop to do, multithreading can only write a file operation but use concurrency to limit, but also improve CPU utilization.
  3. Resource utilization: e.g. 2

Disadvantages:

  1. Security: Variables shared by multiple threads can be problematic
  2. Activity: deadlock
  3. Performance: Multi-threading causes CPU switching to be too expensive and consume too much memory

Concurrent simulation tool

Now we need to prepare a concurrency simulation tool to test whether future code is thread-safe

JMeter, PostMan

To be added

Code to simulate

We’ll use JUC’s utility classes to accomplish the code simulation concurrency scenario

CountDownLatch

Counter latching is a tool that blocks the main thread and allows other threads to continue executing under certain conditions. CountDown to 5000, for example, countDown every time a thread completes an operation to countDown once until count is 0. This guarantees that other threads must be able to perform an operation 5000 times, simulating the number of concurrent executions.

Semaphore

A semaphore is a tool that blocks threads and controls the amount of concurrency for unified time requests. For example, the maximum number of concurrent threads can be 200, simulating a stable concurrency. See article 4 for more details.

Simulation tool


public class ConcurrencyTest { private static final int THREAD_COUNT = 5000; private static final int CONCURRENT_COUNT = 200; private static int count = 0; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Semaphore semaphore = new Semaphore(CONCURRENT_COUNT); CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT); for (int i = 0; i < THREAD_COUNT; i++) { executorService.execute(() -> { try { semaphore.acquire(); add(); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); System.out.println(count); } private static void add(){ count++; }}Copy the code

The result may be 5000 or less than 5000. This proves that the add method is not thread-safe.

reference

Coding.imooc.com/class/195.h… And other hyperlink references

okokokokok

Recently summarized some knowledge points related to Java interview, interested friends can maintain together ~ address: github.com/xbox1994/20…