Thread safe vs. unsafe

Thread safety: when multithreading access, using locking mechanism; That is, when one thread accesses a certain data of this class, the data is protected and cannot be accessed by other threads until the thread finishes reading the data. Prevent data inconsistency or data contamination. Thread unsafe: Multiple threads work on the same data at the same time, causing data inconsistency or contamination.

Code examples:

package thread_5_10; public class Demo26 { static int a = 0; public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100_0000; i++) { a++; }}}); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100_0000; i++) { a--; }}}); // Start thread t1.start(); t2.start(); // wait for the thread to complete //t1.join(); //t2.join(); while(t1.isAlive() || t2.isAlive()){ } System.out.println(a); }}Copy the code

Running results:

493612
Copy the code

Results analysis:

I sorted out some information, and friends in need can click to get it directly.

Java Basics

22 Java Architect Core books

Learning routes and materials from 0 to 1Java

1000+ questions from 2021

Thread unsafe factors:

The CPU executes preemptively (grabbing resources) Multiple threads operate on the same variable visibility non-atomicity compile-time optimization (instruction reordering)

volatile

Volatile is the instruction keyword to ensure that the instruction is not omitted for compile-time optimization and that the value is read directly each time. It can solve memory invisibility and instruction reordering problems, but it cannot solve atomicity problems

Address thread insecurity

There are two ways to lock:

Synchronized (JVM layer solution) Lock

synchronized

The process of handling locks

Synchronized is a JVM level lock solution that implements the process of locking and releasing locks

Code sample

package thread_5_10; Public class Demo31 {private final static int maxSize = 100_0000; Private static int number = 0; Public static void main(String[] args) throws InterruptedException {// Declare the lock Object Object obj = new Object(); Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < maxSize; I++){synchronized (obj){number++; }}}}); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < maxSize; i++) { synchronized (obj){ number--; }}}}); t2.start(); // Wait for both threads to complete t1.join(); t2.join(); System.out.println(number); }}Copy the code

Running results:

0
Copy the code

Resolution:

Pay attention to

Synchronized implementation is divided into:

At the operating system level, it relies on mutex for the JVM, while the Monitor implementation for the Java language stores the lock information in the object header

Three usage scenarios

Use synchronized to modify static methods (which lock the current class) and synchronized to modify ordinary methods (which lock the current class instance) :

package thread_5_10; public class Demo32 { private static int number = 0; private static final int maxSize = 100_0000; public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runnable() { @Override public void run() { increment(); }}); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { decrement(); }}); t2.start(); t1.join(); t2.join(); System.out.println(" final result: "+number); } public synchronized static void increment(){ for (int i = 0; i < maxSize; i++) { number++; } } public synchronized static void decrement(){ for (int i = 0; i < maxSize; i++) { number--; }}}Copy the code

Decorates instance methods:

package thread_5_10; public class Demo33 { private static int number = 0; private static final int maxSize = 100_0000; public static void main(String[] args) throws InterruptedException { Demo33 demo = new Demo33(); Thread t1 = new Thread(new Runnable() { @Override public void run() { demo.increment(); }}); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { demo.decrement(); }}); t2.start(); t1.join(); t2.join(); System.out.println(" final result: "+number); } public synchronized void increment(){ for (int i = 0; i < maxSize; i++) { number++; } } public synchronized void decrement(){ for (int i = 0; i < maxSize; i++) { number--; }}}Copy the code

Manual Lock Lock

Code examples:

package thread_5_10; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo34 { private static int number = 0; private static final int maxSize = 100_0000; Public static void main(String[] args) throws InterruptedException {// Create lock instance lock lock = new ReentrantLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < maxSize; i++) { lock.lock(); try{ number++; }finally { lock.unlock(); }}}}); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < maxSize; i++) { lock.lock(); try{ number--; }finally { lock.unlock(); }}}}); t2.start(); t1.join(); t2.join(); System.out.println(" final result is --> "+number); }}Copy the code

Running results:

The final result is --> 0Copy the code

Matters needing attention:

Lock () must be placed outside the try

If placed in a try, if abnormal inside a try, success is no lock is executed the finally releases the lock code inside, can appear abnormal If placed in a try, if no lock lock is released, this time the exception will put the inside of the business code swallowed up by the abnormal and increase the difficulty of the code debugging

Fair and unfair locks

Fair lock: when a thread releases the lock, it needs to wake up the queue that “needs the lock” to obtain the lock. Unfair lock: When one thread releases the lock, another thread can directly obtain the lock by executing the code that acquires the lock. In The Java language, the default implementation of all locks is unfair lock

Synchronized unfair lock 2. ReentrantLock By default, reentrantLock can be explicitly declared as fair lock

Display declaration fair lock format:

Already the source code:

Example 1:

package thread_5_10; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo36 { public static void main(String[] args) throws InterruptedException { Lock lock = new ReentrantLock(true); Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { lock.lock(); Try {system.out. println(" thread 1"); }finally { lock.unlock(); }}}}); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { lock.lock(); Try {system.out. println(" thread 2"); }finally { lock.unlock(); }}}}); Thread.sleep(1000); t1.start(); t2.start(); }}Copy the code

Running results:

Example 2:

package test; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class test08 { public static void main(String[] args) throws InterruptedException { Lock lock = new ReentrantLock(true); Runnable r = new Runnable() { @Override public void run() { for(char ch: "ABCD".toCharArray()){ lock.lock(); try{ System.out.print(ch); }finally { lock.unlock(); }}}}; Thread.sleep(100); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); }}Copy the code

Running results:

AABBCCDD
Copy the code

The two locks are different

The difference between synchronized and lock

Synchronized is implemented on the JVM level, while Lock is implemented on the Java level. The scope of modification is different. Synchronized can modify code blocks, static methods, Instance method, and Lock can only modify the code block synchronized Lock mode is unfair Lock, while Lock mode is fair Lock and unfair Lock has higher flexibility

A deadlock

Deadlock definition

In two or more threads running, the thread waits because of resource preemption

Deadlock occurs when thread 1 owns resource 1 and tries to acquire resource 2 and thread 2 owns resource 2 and tries to acquire resource 1

Deadlock sample

package thread_5_11; Public class Demo36 {public static void main(String[] args) {lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(new Runnable() {@override public void run() {String threadName = Thread.currentThread().getName(); 1 synchronized (lock1){system.out. println(threadName+" obtain lock1"); Thread.sleep(1000); thread.sleep (1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadName+" waiting lock2"); Synchronized (lock2){system.out.println (threadName+" obtain lock2"); } } } },"t1"); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { String threadName = Thread.currentThread().getName(); Synchronized (lock2){system.out.println (threadName+" obtain lock2"); synchronized (lock2){system.out.println (threadName+" obtain lock2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadName+" waiting lock1"); Synchronized (lock1){system.out.println (threadName+" obtain lock1"); synchronized (lock1){system.out.println (threadName+" obtain lock1"); } } } },"t2"); t2.start(); }}Copy the code

Running results:

Use tools to check deadlocks: (1) JDK – >bin – >jconsole.exe

(2) the JDK – > bin – > jvisualvm. Exe

(3) the JDK – > bin – > JMC. Exe

Four necessary conditions for deadlocks

1. Mutually exclusive condition: when a resource is owned by one thread, it cannot be owned by another thread 2. Hold and wait: when a thread owns a resource it tries to request another resource 3. Non-preemption: When a resource is owned by one thread, it cannot be owned by another thread unless the thread releases the resource. Circular waiting: Two or more threads that have a resource form a loop when they attempt to acquire one another’s resource

Thread communication

Wait (to sleep a thread), notify (to wake up one thread), and notifyall

Wait method

Precautions: 1. Lock the wait method before executing it. Synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized synchronized

Running results:

The main thread wakes up t1 after waitCopy the code

multithreading

package thread_5_13; public class demo40 { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); Thread t1 = new Thread(new Runnable() {@override public void run() {synchronized (lock){ System.out.println("t1 wait before "); lock.wait(); System.out.println("t1 after wait "); } catch (InterruptedException e) { e.printStackTrace(); } } } },"t1"); Thread t2 = new Thread(new Runnable() {@override public void run() {synchronized (lock){ System.out.println("t2 wait before "); lock.wait(); System.out.println("t2 wait after "); } catch (InterruptedException e) { e.printStackTrace(); } } } },"t2"); Thread t3 = new Thread(new Runnable() {@override public void run() {synchronized (lock){ System.out.println("t3 wait before "); lock.wait(); System.out.println("t3 wait after "); } catch (InterruptedException e) { e.printStackTrace(); } } } },"t3"); t1.start(); t2.start(); t3.start(); Thread.sleep(1000); System.out.println(" main thread calls wake up operation "); Synchronized (lock){lock.notify(); }}}Copy the code

Running results:

T1 wait before T2 wait before t3 wait Before the main thread invokes the wake operation t1 wait afterCopy the code

Matters needing attention:

NotifyAll () = lock. Notify () = lock. NotifyAll () = lock. When a wait has an integer greater than 0, it enters a timed_waiting state.

Wait releases locks while waiting, sleep does not release locks while waiting

Compare the wait method with the sleep method

The same: (1) Both wait and sleep can sleep. (2) Both wait and sleep can receive notification to terminate the execution of a thread

Difference: (1) Wait must be synchronized, but sleep does not. (2) Wait releases the lock, and sleep does not. (3) Wait is an Object method, and sleep is a Thread method. If the wait parameter is 0, the thread will be in waiting state and sleep will be in timed_waiting state. (5) If the wait parameter is 0, the thread will be in waiting state

The interview questions

Q: What is the difference between sleep (0) and wait (0)? Q: What is the difference between sleep (0) and wait (0)

2. Why does wait release locks and sleep does not release locks? Sleep must pass a maximum wait time, that is to say, sleep is a controllable level (for the time), and wait that can not pass time, from the design level, if there is no timeout to wait the waiting time under the mechanism of lock is released, then thread may have been blocked, but sleep won’t have this problem

A: Wait requires locking at the Object level (all locks are held in the Object header), not at the Thread level. A Thread can have as many locks as possible

For example, if a thread is interrupted or interrupted by a interrupt, LockSupport can be used for park or unpark. For example, if a thread is interrupted or interrupted by a interrupt, LockSupport can be used to listen for threads that terminate

The last

Now that you’ve seen it, please give it a thumbs up!