当前位置:网站首页>Concurrent shared model management

Concurrent shared model management

2022-06-24 23:11:00 Under the seven kingdoms, I want 99

Concurrent shared model management

1 Sharing issues

Two threads add and subtract the same number , Because of context switching , The value cannot be updated , Thus affecting the statistical results .

static int counter = 0;
public static void main(String[] args) throws InterruptedException {
    
 Thread t1 = new Thread(() -> {
    
 for (int i = 0; i < 5000; i++) {
    
 counter++;
 }
 }, "t1");
 Thread t2 = new Thread(() -> {
    
 for (int i = 0; i < 5000; i++) {
    
 counter--;
 }
 }, "t2");
 t1.start();
 t2.start();
 t1.join();
 t2.join();
 log.debug("{}",counter);
/*  Running results : -2470 */

Problem specification

The above result may be positive 、 negative 、 zero . because Java Autoincrement of static variables in , Self subtraction is not an atomic operation , Analyze from bytecode

about i++ operation , Corresponding JVM Bytecode

getstatic i //  Get static variables i Value 
iconst_1 //  Prepare constants 1
iadd //  Self increasing 
putstatic i //  Store the modified value in a static variable i

about i– operation

getstatic i //  Get static variables i Value 
iconst_1 //  Prepare constants 1
isub //  Self reduction 
putstatic i //  Store the modified value in a static variable i

Java The memory model of is as follows , Complete the self increment of static variables , Self subtraction requires data exchange between main memory and working memory :

 Insert picture description here

Execute... In a single thread , No problem ; In multithreading , Positive numbers may occur , negative .

A critical region

  • There is no problem for a program to run multiple threads
  • The problem is that multiple threads access shared resources
    • The problem is that multiple threads access shared resources
    • Instruction interleaving occurs when multiple threads read and write to shared resources , There will be problems
  • If there are multithreaded read and write operations on shared resources in a code block , Call this code block a critical area

Here is an example :

static int counter = 0;
static void increment() 
//  A critical region 
{
     
 counter++;
}
static void decrement() 
//  A critical region 
{
     
 counter--;
}

Race condition

Multiple threads execute in a critical area , The results are unpredictable due to the different execution sequences of the code , That is, a race condition occurs

2 synchronized

In order to avoid the occurrence of race conditions in the critical region , There are many ways to get there

  • Blocking solutions :synchronized,Lock
  • Non blocking solution : Atomic variable

synchronized, Commonly known as 【 Object lock 】, It uses mutual exclusion to make the same At most one thread at a time can hold 【 Object lock 】, Other threads want to get this again 【 Object lock 】 It will block when . This ensures that you have a lock Threads can safely execute code in critical areas , Don't worry about thread context switching .

java  Mutual exclusion and synchronization in  synchronized  Keyword to complete , The difference between the following :
	 Mutual exclusion is to ensure that the race condition in the critical region occurs , Only one thread can execute critical area code at a time 
      Synchronization is due to the sequence of thread execution 、 Different order 、 A thread needs to wait for other threads to run to a certain point 

grammar

synchronized( object ) //  Threads 1,  Threads 2(blocked)
{
    
  A critical region 
}
//  When a thread 1  Enter the critical area   A context switch occurs ,  Threads 2  Because there is no object lock   Blocked outside 

Case study

static int counter = 0;
static final Object room = new Object();
public static void main(String[] args) throws InterruptedException {
    
 Thread t1 = new Thread(() -> {
    
 for (int i = 0; i < 5000; i++) {
    
 synchronized (room) {
    
 counter++;
 }
 }
 }, "t1");
 Thread t2 = new Thread(() -> {
    
 for (int i = 0; i < 5000; i++) {
    
 synchronized (room) {
    
 counter--;
 }
 }
 }, "t2");
 t1.start();
 t2.start();
 t1.join();
 t2.join();
 log.debug("counter = {}",counter);
}
/*  Running results : counter = 0 */

explain :

  • synchronized( object ) Objects in the , Imagine a room (room), There is only one entrance ( door ) Only one person can enter the room at a time Calculate , Threads t1,t2 Imagine two people

  • When a thread t1 Execute to synchronized(room) Time is like t1 Into this room , And locked the door and took the key , Execute... In the door count++ Code

  • At this time, if t2 Also run to synchronized(room) when , It found the door locked , Can only wait outside the door , A context cut has occurred in , Blocked up

  • Even in the middle t1 Of cpu Unfortunately, the time slice has run out , Kicked out of the door ( Don't mistakenly understand that the object can be locked and executed all the time ), The door was still locked ,t1 Still holding the key ,t2 The thread is still blocked and can't get in , Only next time t1 Only when you get the time slice again Can open the door and enter

  • When t1 After execution synchronized{} Code in block , This is the time to start from obj Come out of the room and unlock the door , Wake up the t2 Thread key Give him the spoon .t2 The thread can then enter obj room , Lock the door, take the key , Carry out its count-- Code

Summary

synchronized In fact, object lock is used to ensure the atomicity of the code in the critical region , The code in the critical area is inseparable from the outside , Will not be cut by the thread Change places to interrupt .

  • If you put synchronized(obj) Put it in for Outside of the loop , How to understand ?

    • So the whole for A cycle is a whole , Before the end of the cycle , Other threads cannot run , Guaranteed atomicity .
  • If t1 synchronized(obj1) and t2 synchronized(obj2) How it will work ?

    • sync It's a lock object . Above , Use two different objects , Then the threads control each other separately , It will not block because of the mutual influence of locks .
  • If t1 synchronized(obj) and t2 What happens if you don't add ?

    • So thread t1 Accuracy is guaranteed , Threads t2 No guarantee , The final result is not guaranteed ,sync A lock is aimed at an object , You need to associate that all threads use the same object .

Object oriented case transformation

//  To control with a lock   Add   reduce   Inquire about 
class Room {
    
 int value = 0;
 public void increment() {
    
 synchronized (this) {
    
 value++;
 }
 }
 public void decrement() {
    
 synchronized (this) {
    
 value--;
 }
 }
 public int get() {
    
 synchronized (this) {
    
 return value;
 }
 }
}

Test class

@Slf4j
public class Test1 {
    
 
 public static void main(String[] args) throws InterruptedException {
    
 Room room = new Room();
 Thread t1 = new Thread(() -> {
    
 for (int j = 0; j < 5000; j++) {
    
 room.increment();
 }
 }, "t1");
 Thread t2 = new Thread(() -> {
    
 for (int j = 0; j < 5000; j++) {
    
 room.decrement();
 }
 }, "t2");
 t1.start();
 t2.start();
 t1.join();
 t2.join();
 log.debug("count: {}" , room.get());
 }
}
/*  Running results : count: 0 */

synchronized Used in methods

Class object

class Test{
    
 public synchronized void test() {
    
 
 }
}
//  Equivalent to 
class Test{
    
 public void test() {
    
 synchronized(this) {
    
 
 }
 }
}

Class itself

class Test{
    
 public synchronized static void test() {
    
 }
}
//  Equivalent to 
class Test{
    
 public static void test() {
    
 synchronized(Test.class) {
    
 
 }
 }
}

Thread eight locks

  • result 12 or 21
@Slf4j(topic = "c.Number")
class Number{
    
 public synchronized void a() {
    
 log.debug("1");
 }
 public synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n1.b(); }).start();
}
  • 1s after 12, or 2 1s after 1
@Slf4j(topic = "c.Number")
class Number{
    
 public synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n1.b(); }).start();
}
  • 3 1s 12 or 23 1s 1 or 32 1s 1
@Slf4j(topic = "c.Number")
class Number{
    
 public synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public synchronized void b() {
    
 log.debug("2");
 }
 public void c() {
    
 log.debug("3");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n1.b(); }).start();
 new Thread(()->{
     n1.c(); }).start();
}
  • 2 1s after 1
@Slf4j(topic = "c.Number")
class Number{
    
 public synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 Number n2 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n2.b(); }).start();
}
  • 2 1s after 1
@Slf4j(topic = "c.Number")
class Number{
    
 public static synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n1.b(); }).start();
}
  • 1s after 12, or 2 1s after 1
@Slf4j(topic = "c.Number")
class Number{
    
 public static synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public static synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n1.b(); }).start();
}

  • 2 1s after 1
@Slf4j(topic = "c.Number")
class Number{
    
 public static synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 Number n2 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n2.b(); }).start();
}
  • 1s after 12, or 2 1s after 1
@Slf4j(topic = "c.Number")
class Number{
    
 public static synchronized void a() {
    
 sleep(1);
 log.debug("1");
 }
 public static synchronized void b() {
    
 log.debug("2");
 }
}
public static void main(String[] args) {
    
 Number n1 = new Number();
 Number n2 = new Number();
 new Thread(()->{
     n1.a(); }).start();
 new Thread(()->{
     n2.b(); }).start();
}
原网站

版权声明
本文为[Under the seven kingdoms, I want 99]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/175/202206241726205084.html