Home > Java > JavaBase > body text

Java introduces Lock and producer-consumer issues

coldplay.xixi
Release: 2021-02-09 17:43:21
forward
2728 people have browsed it

Java introduces Lock and producer-consumer issues

Free learning recommendation: java basic tutorial

Lock lock and producer-consumer issues

  • Traditional Synchronized lock
  • Lock lock
  • The difference between Synchronized and lock lock
  • Traditional producer and consumer issues
  • Lock version of producer and consumer issues
  • Condition to achieve precise notification wake-up

Traditional Synchronized lock

Implement a basic ticket sales example:

/*
真正的多线程开发,公司中的开发,降低耦合性
线程就是一个单独的资源类,没有任何附属的操作
1.属性,方法
 * */public class SaleTicketDemo1 {
    public static void main(String[] args) {
        //并发,多个线程操作同一个资源类,把资源类丢入线程
        Ticket ticket=new Ticket();
        //Runnable借口是一个FunationalInterface函数式接口,接口可以new,jdk1.8以后,lamda表达式()->{代码}
        new Thread(()->{
            for(int i=0;i{
            for(int i=0;i0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
        }
    }}
Copy after login

Note that lambda expressions are used here. For detailed descriptions of lambda expressions, see Java Basics-Lambda Expressions

Java introduces Lock and producer-consumer issues
This is to use traditional synchronized to achieve concurrency. The essence of synchronized is queues and locks. It's like queuing up in a cafeteria. If there is no queue, it will be chaotic. Only when the service to one person is completed can the other person receive the service.

Lock

As mentioned before, the JVM provides the synchronized keyword to achieve synchronous access to variables and use wait and notify to implement inter-thread communication. After jdk1.5, JAVA provides the Lock class to implement the same functions as synchronized, and also provides Condition to display inter-thread communication.
The Lock class is a function provided by the Java class. The rich API makes the synchronization function of the Lock class more powerful than synchronized synchronization.
In the java.util. Concurrent package, there are 3 interfaces, Condition and lock (standard lock). ReadWriteLock lock (read-write lock)
Lock implementation provides a wider range of locking operations than can be obtained using synchronized methods and statements. They allow for more flexible structuring, may have completely different properties, and can support multiple associated object Conditions.

Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
Copy after login

lock() means locking, unlock() means unlocking
Explained in the JDK official document
Java introduces Lock and producer-consumer issues
All have been Known implementation class:
ReentrantLock reentrant lock
ReentrantReadWriteLock.ReadLock read lock
ReentrantReadWriteLock.writeLock write lock

Let’s talk about the ReentrantLock implementation class first:
ReentrantLock underlying source code constructor
Java introduces Lock and producer-consumer issues
Fair lock: very fair, first come, first served. But the problem is that if a 3s and a 3h process arrive, 3h comes first, then 3s waits for 3h, which is actually not good.
Unfair lock: Very unfair, you can jump the queue (default)
We will explain it in detail later.

How to use, lock before use, unlock after use

//lock lock trilogy
//1.new ReentranLock() ;Construction
//2.Lock.lock();Lock
//3.finally();Unlock

public class SaleTicketDemo2 {
	public static void main(String[] args) {
		//并发,多个线程操作同一个资源类,把资源类丢入线程
		Ticket ticket=new Ticket();
		//Runnable借口是一个FunationalInterface函数式接口,接口可以new,jdk1.8以后,lamda表达式()->{代码}
		new Thread(()->{for(int i=0;i{for(int i=0;i{for(int i=0;i0){
				System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}	
	}}
Copy after login

The difference between Synchronized and lock lock

1.synchronized is a built-in java keyword, lock is a Java class
2.synchronized cannot determine the status of acquiring the lock, lock can determine whether the lock has been acquired
3.synchronized will automatically To release the lock (a–), the lock must be released manually! If the lock is not released, it will lead to deadlock
4. Synchronized thread 1 (obtaining the lock, blocking), thread 2 (waiting, waiting stupidly)
lock.tryLock() tries to acquire the lock, which may not always happen Wait
5. Synchronized reentrant lock, uninterruptible, unfair lock. Lock, reentrant lock, can judge the lock, fair and unfair can be set by yourself (can be set by yourself)
6. synchronized is suitable for a small amount of code synchronization problems, lock lock is suitable for locking a large amount of synchronized code
synchornized lock object and synchronized code block method

Traditional producer and consumer issues

Traditional producers and consumers are based on the wait, notify method and synchronized key of the Object class Words are used to achieve this.
During interviews, it is very common to hand-write producer and consumer code.
Classic questions in the interview written test:
Singleton mode sorting algorithm producer-consumer deadlock
Synchronized version of producer-consumer problem

Communication problem between threads: producer Waiting for wake-up with consumer issues, notification wake-up
Threads alternately execute A B to operate the same variable number=0
A num 1
B num-1

Note: is locked In the method, the idea of ​​​​execution is to judge and wait for business notification

package testConcurrent;/*
线程之间的通信问题:生产者和消费者问题    等待唤醒,通知唤醒
线程交替执行 A B 操作同一个变量number=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{
			for(int i=0;i"+number);
		//通知其他线程,我+1完毕了
		this.notify();
	}
	//-1
	public synchronized void decrement() throws InterruptedException{
		if(number==0){
			//等待
			this.wait();
		}
		number--;
		System.out.println(Thread.currentThread().getName()+"=>"+number);
		//通知其他线程,我-1完毕了
		this.notify();
	}}
Copy after login

Java introduces Lock and producer-consumer issues
As shown in the figure, the required functions can basically be achieved, but problems will still occur. If I try again at this time Adding two threads, then

		new Thread(()->{
			for(int i=0;i{
			for(int i=0;i<p><img src="https://img.php.cn/upload/article/000/000/052/4011c6e510a595c0afc39326e031cf33-4.png" alt="Java introduces Lock and producer-consumer issues"><br> 这里结果中出现了2,输出结果出现了问题。为什么呢?<br> 为什么if判断会出现问题:<br> if判断只判断一次。因为if判断了之后,就已经进入了代码的等待那一行,这时,在wait下的线程可能有多个,甚至包括生产者和消费者。有可能某个生产者执行完了之后,唤醒的是另一个生产者。</p><p>在我们的官方文档中就给出了解释</p><pre class="brush:php;toolbar:false">public final void wait(long timeout)
                throws InterruptedException
Copy after login

导致当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法,或指定的时间已过。
线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒 。 虽然这在实践中很少会发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。 换句话说,等待应该总是出现在循环中,就像这样:

 synchronized (obj) {
         while (<condition>)
             obj.wait(timeout);
         ... // Perform action appropriate to condition
     }</condition>
Copy after login

注意点:防止虚假唤醒问题
我们代码中用的是if判断,而应该用while判断

package testConcurrent;/*
线程之间的通信问题:生产者和消费者问题    等待唤醒,通知唤醒
线程交替执行 A B 操作同一个变量number=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{
            for(int i=0;i{
            for(int i=0;i{
            for(int i=0;i"+number);
        //通知其他线程,我+1完毕了
        this.notify();
    }
    //-1
    public synchronized void decrement() throws InterruptedException{
        while(number==0){
            //等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        //通知其他线程,我-1完毕了
        this.notify();
    }}
Copy after login

Lock版的生产者和消费者问题

在synchronized版本中,我们使用了wait和notify来实现线程之间的同步
在lock中,
此时synchronized被lock替换了,那么wait和notify用什么来替换呢?
我们在官方文档java.util.concurrent.locks 中,找到Lock类,然后在底部找到了
Condition newCondition()
返回一个新Condition绑定到该实例Lock实例。
在等待条件之前,锁必须由当前线程保持。 呼叫Condition.await()将在等待之前将原子释放锁,并在等待返回之前重新获取锁。

然后我们再来了解Condition类
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
一个Condition实例本质上绑定到一个锁。 要获得特定Condition实例的Condition实例,请使用其newCondition()方法。

Java introduces Lock and producer-consumer issues
我们可以看到,使用的时候new一个Condition对象。然后用await替代wait,signal替换notify
代码实现
//判断等待+业务+通知

class Data2{		//数字。资源类
	private int number=0;
	Lock lock=new ReentrantLock();
	Condition condition=lock.newCondition();
	//+1
	public void increment() throws InterruptedException{
		try {
			lock.lock();
			//业务代码
			while(number!=0){		
				//等待
				condition.await();
			}
			number++;		
			System.out.println(Thread.currentThread().getName()+"=>"+number);
			condition.signalAll();		//通知
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}
	//-1
	public void decrement() throws InterruptedException{
		try {
			lock.lock();
			//业务代码
			while(number!=1){		
				//等待
				condition.await();
			}
			number--;		
			System.out.println(Thread.currentThread().getName()+"=>"+number);
			condition.signalAll();		//通知
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}	}
Copy after login

注意:主函数部分于最上面的代码一样。

Java introduces Lock and producer-consumer issues
这时候虽然说是正确的,但是它是一个随机分布的状态,现在我们希望它有序执行,即A执行完了执行B,B执行C,C完了执行D。即精准通知。

Condition实现精准通知唤醒

Condition实现精准的通知和唤醒
我们构造三个线程,要求A执行完了执行B,B执行完了执行C,C执行完了执行D.
代码思想:
//加多个监视器,通过监视器来判断唤醒的是哪一个人
//设置多个同步监视器,每个监视器监视一个线程
//实例:生产线,下单->支付->交易->物流

package testConcurrent;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*
A执行完调用B,B执行完调用C,C执行完调用A
 * */public class C {

    public static void main(String[] args) {
        Data3 data=new Data3();
        new Thread(()->{
            for(int i=0;i{
            for(int i=0;i{
            for(int i=0;i支付->交易->物流
    private Condition condition1=lock.newCondition();
    private Condition condition2=lock.newCondition();
    private Condition condition3=lock.newCondition();
    private int number=1;       //1A 2B 3C
    public void printA(){
        lock.lock();
        try {
            //业务,判断->执行->通知
            while(number!=1){
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
            //唤醒,唤醒指定的人,B
            number=2;           //精准唤醒
            condition2.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }   
    public void printB(){
        lock.lock();
        try {
            //业务,判断->执行->通知
            while(number!=2){
                //等待
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBB");
            //唤醒,唤醒指定的人,C
            number=3;           //精准唤醒
            condition3.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            //业务,判断->执行->通知
            while(number!=3){
                //等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>CCCCCCC");
            //唤醒,唤醒指定的人,A
            number=1;           //精准唤醒
            condition1.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }}
Copy after login

相关学习推荐:java基础

The above is the detailed content of Java introduces Lock and producer-consumer issues. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:csdn.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template