JUC Concurrent Programming Study Notes

1: Review multithreading

What are processes and threads?
A process is the smallest unit for resource allocation by the operating system, and a thread is the smallest unit for cpu scheduling.

  • Java has several threads
    2 by default, main thread and GC thread (GC garbage collection mechanism)

  • Can java start threads?
    No

  • Concurrency and Parallel
    Concurrency, multi-thread operation on the same resource, single-core cpu, simulate multiple threads, fast alternate parallelism
    , multiple people walking together, multi-core cpu, multiple threads can execute at the same time, thread pool

package main;
public class Demo1 {
    public static void main(String[] args) {
        //获取cpu的核数
        //cpu密集型,io密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

Example:

A thread has several states:

Thread.State

    public enum State {
        /**
         * 新建状态
         */
        NEW,

        /**
         * 运行状态
         */
        RUNNABLE,

        /**
         * 堵塞状态
         */
        BLOCKED,

        /**
         * 等待状态
         */
        WAITING,

        /**
         * 超时等待
         */
        TIMED_WAITING,

        /**
         * 终止状态
         */
        TERMINATED;
    }

1.1 The difference between wait/sleep

1. From different classes, wait->Object, sleep->Thread
2. Lock release, wait->release lock, sleep->do not release lock
3. Use range, wait->synchronous code block, sleep->anywhere

1.2 synchronized lock 

package main;
/*
* 真正的多线程开发,公司中的开发,降低耦合型
* 线程就是一个单独的资源类,没有任何附属的操作!
* 1. 属性  方法
* */
public class TicketSale {
    public static void main(String[] args) {
        //并发:多线程操作同一个资源类,把资源丢入线程
        Ticket ticket = new Ticket();
        //@FunctionalInterface 函数式接口,jkd1.8 lambda 表达式(参数)->{代码}
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}
//资源类OOP
class  Ticket{
    //属性  方法
    private int number = 30;
    //卖票的方式
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
        }
    }
}

1.3 Lock lock

Class ReentrantLock constructor
public ReentrantLock() Create an instance of ReentrantLock. This is equivalent to using ReentrantLock(false)
public ReentrantLock(boolean fair) Creates an instance of ReentrantLock according to the given fairness policy. fair - true if this lock should use a fair ordering policy

1.3.1 What are fair locks and unfair locks?

  • Unfair lock: You can jump in the queue (no parameter construction method defaults to unfair lock)
  • Fair lock: first come, first come (fair lock when there is a construction method with parameters and the value is true)
package main;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
 * 真正的多线程开发,公司中的开发,降低耦合型
 * 线程就是一个单独的资源类,没有任何附属的操作!
 * 1. 属性  方法
 * */
public class TicketSale2 {
    public static void main(String[] args) {
        //并发:多线程操作同一个资源类,把资源丢入线程
        Ticket2 ticket = new Ticket2();
        //@FunctionalInterface 函数式接口,jkd1.8 lambda 表达式(参数)->{代码}
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}
/*
* lock三部曲
* 1.new ReentrantLock()
* 2.lock.lock();//加锁
* 3.finally-> lock.unlock() //解锁
* */
class  Ticket2{
    //属性  方法
    private int number = 30;
    //卖票的方式
    Lock lock = new ReentrantLock();
    public  void sale(){
        lock.lock();//加锁
        try {
            //业务代码
            if (number>0){
                System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//解锁
        }
    }
}



/*
公平锁
线程1购买了第10张票
线程2购买了第9张票
线程3购买了第8张票
线程1购买了第7张票
线程2购买了第6张票
线程3购买了第5张票
线程1购买了第4张票
线程2购买了第3张票
线程3购买了第2张票
线程1购买了第1张票
非公平锁
线程1购买了第10张票
线程1购买了第9张票
线程1购买了第8张票
线程1购买了第7张票
线程1购买了第6张票
线程1购买了第5张票
线程1购买了第4张票
线程1购买了第3张票
线程1购买了第2张票
线程1购买了第1张票
*/

1.4 The difference between synchronized and Lock

  1. lock is an interface, and synchronized is a keyword of java.
  2. Synchronized will automatically release the occupied lock when an exception occurs, so there will be no deadlock; and when the lock occurs abnormally, it will not actively release the occupied lock, and the lock must be released manually, which may cause deadlock.
  3. Synchronized reentrant lock, uninterruptible, unfair; Lock, reentrant lock, can judge lock, unfair (can be set by yourself);
  4. Synchronized is suitable for locking a small amount of code synchronization problems, and Lock is suitable for locking a large number of synchronization codes!
  5. Synchronized thread 1 (obtain lock, block), process 2 (wait, silly, etc.); Lock lock does not necessarily wait;
  6. Synchronized cannot judge the status of acquiring the lock, but Lock can determine whether the lock has been acquired

synchronized

Lock

Producers and consumers of the 1.5 synchronized version 

package pc;
/*
* 线程之间的通信问题:生产者和消费者问题 等待唤醒 ,通知唤醒
* 线程交替执行  A  B  操作同一个变量  num = 0;
* A num+1
* B num-1
* */
public class A {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
//等待 业务 通知
class Data{//数字  资源类
    private  int number = 0;
    public  synchronized void increment() throws InterruptedException {
        if (number != 0) {
            //等待
            this.wait();
        }
        number++;
        //通知其他线程,我+1完毕了
        System.out.println(Thread.currentThread().getName()+"-->"+number);
        this.notifyAll();
    }
    public synchronized void decrement() throws InterruptedException {
        if (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"-->"+number);
        this.notifyAll();
    }
}

1.6 Prevent false wake-up problems

When there are four threads (two producers and two consumers), there is a false wake-up problem. You need to use while to replace if to judge whether it can continue to execute after wake-up. Understanding:
Take two addition threads A and B, for example, A executes first , the wait method is called during execution, then it will wait, and the lock will be released at this time, then thread B will acquire the lock and will also execute the wait method, and the two plus threads will wait together to be awakened. At this time, one of the threads in the minus thread finishes executing and wakes up the two plus threads, then the two plus threads will not execute together, where A acquires the lock and adds 1, and B will execute after the execution is completed. If it is if, then after A modifies num, B will not judge the value of num, and will directly give num+1. If it is while, after A is executed, B will also judge the value of num, so it will not execute

package pc;
/*
* 线程之间的通信问题:生产者和消费者问题 等待唤醒 ,通知唤醒
* 线程交替执行  A  B  操作同一个变量  num = 0;
* A num+1
* B num-1
* */
public class A {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
//等待 业务 通知
class Data{//数字  资源类
    private  int number = 0;
    public  synchronized void increment() throws InterruptedException {
        while (number != 0) {
            //等待
            this.wait();
        }
        number++;
        //通知其他线程,我+1完毕了
        System.out.println(Thread.currentThread().getName()+"-->"+number);
        this.notifyAll();
    }
    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"-->"+number);
        this.notifyAll();
    }
}

 1.7 JUC version of the producer consumer problem Lock Condition

await:

 signalAll:

package pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class B {
    public static void main(String[] args) {
        Data2 data = new Data2();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
//等待 业务 通知
class Data2 {//数字  资源类
    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
//    condition.await();//等待
//    condition.signalAll();//唤醒全部
    public void increment() throws InterruptedException {
        lock.lock();
        try {
            //业务代码
            while (number != 0) {
                //等待
                condition.await();
            }
            number++;
            //通知其他线程,我+1完毕了
            System.out.println(Thread.currentThread().getName() + "-->" + number);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "-->" + number);
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

1.8 Condition Realize precise notification wake-up

await:

 signal:

package pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class C {
    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 {// 资源类 Lock
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int number = 1;
    public void printA() {
        lock.lock();
        try {
            //业务,判断->执行->通知
            while (number != 1) {
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "--->A");
            //唤醒指定的人:B
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB() {
        lock.lock();
        try {
            //业务,判断->执行->通知
            while (number != 2) {
                //等待
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "--->B");
            //唤醒指定的人:C
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC() {
        lock.lock();
        try {
            //业务,判断->执行->通知
            while (number!=3){
                //等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"--->C");
            number=1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

1.9 Understanding of Eight-lock Phenomenon

 The same lock: the object of the synchronized lock is the caller of the method (phone)

package lock;
import java.util.concurrent.TimeUnit;
/*
 * 1.标准情况下,两个线程先打印发短信还是打电话?1.发短信﹑2.打电话
 * 2.sendSms延迟4秒,两个线程先打印 发短信还是 打电话?1.发短信 2.打电话
 * */
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        //锁的存在
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}
class Phone{
    //synchronized 锁的对象是方法的调用者
    //两个方法是同一个锁,谁先拿到谁先执行
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

result:


 Two objects are not using a lock: phone, phone2

package com.example.juc.test;
import java.util.concurrent.TimeUnit;
/*
 * 3.增加了一个普通方法,先发短信还是Hello
 * 4.两个对象,两个同步方法,先发短信还是先打电话
 * */
public class Demo1 {
   public static void main(String[] args) throws InterruptedException {
      //两个对象,两个调用者,两把锁!
      Phone phone = new Phone();
      Phone phone2 = new Phone();
      //锁的存在
      new Thread(()->{
         System.out.println(Thread.currentThread().getName());
         phone.hello();
         phone.sendSms();
      },"A").start();
      TimeUnit.SECONDS.sleep(1);
      new Thread(()->{
         System.out.println(Thread.currentThread().getName());
         phone2.hello();
         phone2.call();
      },"B").start();
   }
}
class Phone{
   //synchronized 锁的对象是方法的调用者
   //两个方法是同一个锁,谁先拿到谁先执行
   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");
   }
}

result:


package com.example.juc.test;
import java.util.concurrent.TimeUnit;
/*
 * 5.增加两个静态的同步方法,只有一个对象,先打印 发短信还是打电话
 * 6.两个对象!增加两个静态的同步方法, 先打印 发短信还是打电话
 * */
public class Demo1 {
   public static void main(String[] args) throws InterruptedException {
      //两个对象的Class类模板只有一个,static,锁的是Class
      Phone phone = new Phone();
      Phone phone2 = new Phone();
      //锁的存在
      new Thread(()->{
         phone.sendSms();
      },"A").start();
      TimeUnit.SECONDS.sleep(1);
      new Thread(()->{
         phone2.call();
      },"B").start();
   }
}
//Phone唯一的一个Class对象
class Phone{
   //synchronized 锁的对象是方法的调用者
   //static 静态方法
   //类一加载就有了!锁的是Class
   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("打电话");
   }
}

result:


package com.example.juc.test;
import java.util.concurrent.TimeUnit;
/*
 * 7.1个静态的同步方法,1个普通的同步方法,1个对象,先打印谁
 * 8.1个静态的同步方法,1个普通的同步方法,2个对象,先打印谁
 * */
public class Demo1 {
   public static void main(String[] args) throws InterruptedException {
      //两个对象的Class类模板只有一个,static,锁的是Class
      Phone phone = new Phone();
      Phone phone2 = new Phone();
      //锁的存在
      new Thread(() -> {
         phone.sendSms();
      }, "A").start();
      TimeUnit.SECONDS.sleep(1);
      new Thread(() -> {
         phone2.call();
      }, "B").start();
   }
}
//Phone唯一的一个Class对象
class Phone {
   //静态的同步方法  锁的是Class类模板
   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("打电话");
   }
}

result:

Continuously updating........

Guess you like

Origin blog.csdn.net/XikYu/article/details/131208778