[JUC multi-threaded learning] thread, concurrency and parallelism, Synchronized and Lock, eight-lock problem

JUC multithreading

How many threads does java have by default?

2 one is main and one is GC (garbage collection).

Can java start threads by itself?

Java cannot open threads, it can only be called through local methods, and Java cannot directly operate hardware.

Concurrency and Parallelism

Concurrency: Multiple threads execute alternately at the same time interval

Parallelism: multiple threads execute at the same time

Threads have 6 states:

  • NEW Freshmen
  • RUNNABLE run
  • BLOCKED blocked
  • WATING
  • TIMED_WATING timed out waiting
  • TEMINATED terminated

The difference between wait and sleep

1. From different classes

wait from Object

sleep from Thread

2. About the release of the lock

wait will release the lock, sleep sleeps, sleeps with the lock, and will not release it.

3. The scope of use is different

wait must be in a synchronous code block

sleep can be anywhere

4. Do you need to catch exceptions?

wait does not need to catch exceptions

sleep must catch exceptions

Lock

Traditional Synchronized

Without locking:

Please add a picture description

the result will be out of order

Add a lock to the sale method

Please add a picture description

The result is normal.

public class saleTicketDemo01 {
    
    
    public static void main(String[] args) {
    
    
        //并发: 多线程操作同一个资源类,把资源类丢入线程
        final Ticket ticket = new Ticket();

        new Thread(()->{
    
    //lambda表达式 (参数)->{}
            for (int i=0;i<50;i++)
                ticket.sale();
        },"A").start();

        new Thread(()->{
    
    
            for (int i=0;i<50;i++)
                ticket.sale();
        },"B").start();

        new Thread(()->{
    
    
            for (int i=0;i<50;i++)
                ticket.sale();
        },"C").start();

    }
}

class Ticket{
    
    
    //票的数量
    private int num = 30;

    //卖票的操作
    public synchronized void sale(){
    
    
        if(num>0)
            System.out.println("卖出第"+(30-num+1)+"张票,还剩"+(--num)+"票");
    }
}

Lock lock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class saleTicketDemo02 {
    
    
    public static void main(String[] args) {
    
    
        //并发: 多线程操作同一个资源类,把资源类丢入线程
        final Ticket2 ticket = new Ticket2();

        new Thread(()->{
    
    //lambda表达式 (参数)->{}
            for (int i=0;i<50;i++)
                ticket.sale();
        },"A").start();

        new Thread(()->{
    
    
            for (int i=0;i<50;i++)
                ticket.sale();
        },"B").start();

        new Thread(()->{
    
    
            for (int i=0;i<50;i++)
                ticket.sale();
        },"C").start();

    }
}

class Ticket2{
    
    
    //票的数量
    private int num = 30;
    private Lock lock = new ReentrantLock();
    //卖票的操作
    public void sale(){
    
    
        lock.lock();//上锁
        try{
    
    
            if(num>0)
                System.out.println("卖出第"+(30-num+1)+"张票,还剩"+(--num)+"票");
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();//解锁
        }

    }
}

The difference between Synchronized and Lock

1. Synchronized is a built-in keyword in java, and Lock is a java class

2. Synchronized cannot judge the status of the lock acquisition. Lock can judge whether the lock has been acquired.

3. Synchronized will automatically release the lock. Lock must be released manually. If the lock is not released, it will be deadlocked.

4. Synchronized thread 1 (acquires the lock), thread 2 (waiting, stupidly waiting) Lock lock does not necessarily wait

5. Synchronized reentrant locks cannot be interrupted, which is unfair; Lock is reentrant, you can judge the lock, and you can set fairness or unfairness by yourself

6. Synchronized is suitable for locking a small amount of code synchronization issues, and Lock is suitable for locking a large number of synchronization codes.

producer consumer problem

Traditional Synchronized implementation

public class demo01 {
    
    

    public static void main(String[] args) {
    
    
        Data data = new Data();
        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                try {
    
    
                    data.decrement();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                try {
    
    
                    data.increment();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"B").start();
    }

}

//信号量 资源类
class Data{
    
    
    private int num = 0;

    //生产者
    public synchronized void increment() throws InterruptedException {
    
    
        if(num!=0){
    
    
            //等待
            this.wait();
        }
        num++;
        System.out.println(num);
        //唤醒
        this.notifyAll();
    }
    //消费者
    public synchronized void decrement() throws InterruptedException {
    
    
        if(num==0){
    
    
            //等待
            this.wait();
        }
        num--;
        System.out.println(num);
        //唤醒
        this.notifyAll();
    }
}

existing problems

There is no problem with two threads, but there will be problems with multiple threads

To prevent spurious wakeup, wait needs to be placed in a loop

Change if to while judgment

Producer consumer of JUC version

Obtain conditon through lock

condition.await() awaits

condition.signalAll() wakes up all

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class demo02 {
    
    

    public static void main(String[] args) {
    
    
        Data2 data = new Data2();
        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.increment();
            }
        },"A").start();

        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.decrement();
            }
        },"B").start();

        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.increment();
            }
        },"C").start();

        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.decrement();
            }
        },"D").start();
    }

}

//信号量 资源类
class Data2{
    
    
    private int num = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    //生产者
    public  void increment()  {
    
    
        lock.lock();
        try{
    
    
            while(num!=0){
    
    
                //等待
                condition.await();
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"=>"+num);
            //唤醒
            condition.signalAll();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }

    }
    //消费者
    public synchronized void decrement(){
    
    
        lock.lock();
        try{
    
    
            while(num==0){
    
    
                //等待
                condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"=>"+num);
            //唤醒
            condition.signalAll();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }
}

Problem: Out-of-order state of threads

To enable it to execute ABCD in an orderly manner

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class demo03 {
    
    
    public static void main(String[] args) {
    
    
        Data3 data = new Data3();
        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.printA();
            }
        },"A").start();

        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.printB();
            }
        },"B").start();

        new Thread(()->{
    
    
            for (int i = 0; i < 10; i++) {
    
    
                data.printC();
            }
        },"C").start();
    }
}

class Data3{
    
    
    private int num = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void printA(){
    
    
        lock.lock();
        try {
    
    
            while(num!=1){
    
    
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAA");
            num=2;
            condition2.signal();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }

    public void printB(){
    
    
        lock.lock();
        try {
    
    
            while(num!=2){
    
    
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBB");
            num=3;
            condition3.signal();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }

    public void printC(){
    
    
        lock.lock();
        try {
    
    
            while(num!=3){
    
    
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>CCCC");
            num=1;
            condition1.signal();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();
        }
    }
}

eight-lock problem

  • The object of the lock is the caller of the method
  • Not synchronized methods are not affected by locking
  • The static static method class has a lock as soon as it is loaded is the Class class template ( the only one )
import java.util.concurrent.TimeUnit;

//1,标准情况下,两个线程先打印  发短信 还是  打电话?   发短信
//2,标准情况下,发短信方法sleep 4s 两个线程先打印  发短信 还是  打电话?   发短信
public class test01 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone phone = new Phone();

        new Thread(()->{
    
    
            phone.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone.call();
        }).start();

    }
}

class Phone{
    
    

    public synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call(){
    
    
        System.out.println("打电话");
    }
}

Because the object of the lock is the caller of the method, the two methods use the same lock. Whoever gets it first will execute first

import java.util.concurrent.TimeUnit;

//3,增加一个普通方法,两个线程先打印  发短信 还是  hello?   hello
public class test02 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone2 phone = new Phone2();

        new Thread(()->{
    
    
            phone.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone.hello();
        }).start();

    }
}

class Phone2{
    
    

    public synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call(){
    
    
        System.out.println("打电话");
    }

    public void hello(){
    
    
        System.out.println("hello");
    }
}

Because ordinary methods do not have locks, they are not synchronized methods and are not affected by locks.

import java.util.concurrent.TimeUnit;

//4,两个对象 都是同步方法  先打印  发短信 还是  打电话?   打电话
public class test02 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();

        new Thread(()->{
    
    
            phone1.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone2.call();
        }).start();

    }
}

class Phone2{
    
    

    public synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call(){
    
    
        System.out.println("打电话");
    }
    
}

Because there are two objects now, the phone1 object is locked for sending text messages, and the phone2 object is locked for calling, which are two locks

import java.util.concurrent.TimeUnit;

//5,两个静态同步方法  先打印  发短信 还是  打电话?   发短信
public class test03 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone3 phone = new Phone3();

        new Thread(()->{
    
    
            phone.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone.call();
        }).start();

    }
}
//只有唯一的一个Class对象
class Phone3{
    
    

    public static synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public static synchronized void call(){
    
    
        System.out.println("打电话");
    }


Because the static static synchronization method locks the Class template, so the text message method is taken first, and the call can only wait

import java.util.concurrent.TimeUnit;

//6,两个静态同步方法,两个对象  先打印  发短信 还是  打电话?   发短信
public class test03 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        //两个对象只有一个Class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();
        new Thread(()->{
    
    
            phone1.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone2.call();
        }).start();

    }
}

class Phone3{
    
    

    public static synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public static synchronized void call(){
    
    
        System.out.println("打电话");
    }

}

The static synchronization method locks Class, and there is only one lock, so phone1 takes it first, prints and sends text messages first

import java.util.concurrent.TimeUnit;

//7,一个普通同步方法,一个静态同步方法,  先打印  发短信 还是  打电话?   打电话
public class test04 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone4 phone = new Phone4();

        new Thread(()->{
    
    
            phone.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone.call();
        }).start();

    }
}

class Phone4{
    
    

    public static synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call(){
    
    
        System.out.println("打电话");
    }

}

Because there are two locks here, the static synchronization method locks the Class, and the ordinary synchronization method locks the caller

import java.util.concurrent.TimeUnit;

//8,一个普通同步方法,一个静态同步方法,两个对象  先打印  发短信 还是  打电话?   打电话
public class test04 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();

        new Thread(()->{
    
    
            phone1.sendSms();
        }).start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
    
    
            phone2.call();
        }).start();

    }
}

class Phone4{
    
    

    public static synchronized void sendSms(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call(){
    
    
        System.out.println("打电话");
    }

}

Same as 7, the two do not use the same lock

Guess you like

Origin blog.csdn.net/adminguojieBin/article/details/123670331