Multithreading communication

Posted by McManCSU on Fri, 29 Nov 2019 13:50:15 +0100

Multithreading concurrency is mainly multithreading operation resource class, followed by multithreading communication, trilogy, judgment, work, and notification. In order to prevent false wake-up judgment, while must be used. Finally, in order to ensure the order of multithreading execution, Condition matching flag bit can be used to notify the designated thread to wake up.

bounded-buffer problem

Two threads operate the air conditioning resource class, one heating degree, one desuperheating degree, one return, 10 cycles

Version 1

Trilogy of communication among multiple threads, judgment, work, notice and wake up other threads

package com.zbiti.juc;


//High cohesion and low coupling, multithreaded operation resource class
//Multithreaded communication judgment / work / notification to prevent false wake-up judgment
public class ProducerConsumerDemo {
    public static void main(String[] args) {
        AirConditon airConditon = new AirConditon();
        new Thread(()->{
            try {
                for(int i=1;i<=10;i++){
                    airConditon.increament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"AA").start();

        new Thread(()->{
            try {
                for(int i=1;i<=10;i++){
                    airConditon.decreament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"BB").start();
    }
}


//Air conditioning resources with plus degree and minus degree functions
class AirConditon {
    int number = 0;


    synchronized void increament() throws Exception {
        //judge
        if (number != 0) {
            this.wait();
        }

        //work
        number++;
        System.out.println(Thread.currentThread().getName()+"\t"+number);

        //notice
        this.notifyAll();
    }


    synchronized void decreament() throws Exception {

        //judge
        if (number != 1) {
            this.wait();
        }

        //work
        number--;
        System.out.println(Thread.currentThread().getName()+"\t"+number);

        //notice
        this.notifyAll();
    }

}

Result

The result is correct at this time

AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0

Process finished with exit code 0

If it's four threads, two producers and two consumers

package com.zbiti.juc;


//High cohesion and low coupling, multithreaded operation resource class
//Multithreaded communication judgment / work / notification to prevent false wake-up judgment
public class ProducerConsumerDemo {
    public static void main(String[] args) {
        AirConditon airConditon = new AirConditon();
        new Thread(()->{
            try {
                for(int i=1;i<=10;i++){
                    airConditon.increament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"AA").start();

        new Thread(()->{
            try {
                for(int i=1;i<=10;i++){
                    airConditon.decreament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"BB").start();

        new Thread(()->{
            try {
                for(int i=1;i<=10;i++){
                    airConditon.increament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"CC").start();

        new Thread(()->{
            try {
                for(int i=1;i<=10;i++){
                    airConditon.decreament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"DD").start();
    }
}


//Air conditioning resources with plus degree and minus degree functions
class AirConditon {
    int number = 0;


    synchronized void increament() throws Exception {
        //judge
        if (number != 0) {
            this.wait();
        }

        //work
        number++;
        System.out.println(Thread.currentThread().getName()+"\t"+number);

        //notice
        this.notifyAll();
    }


    synchronized void decreament() throws Exception {

        //judge
        if (number != 1) {
            this.wait();
        }

        //work
        number--;
        System.out.println(Thread.currentThread().getName()+"\t"+number);

        //notice
        this.notifyAll();
    }

}

Result

We can see that the result is not in line with our expectation

AA	1
DD	0
CC	1
AA	2
CC	3
DD	2
CC	3
BB	2
AA	3
BB	2
CC	3
DD	2
CC	3
BB	2
AA	3
BB	2
CC	3
DD	2
CC	3
BB	2
AA	3
BB	2
CC	3
DD	2
CC	3
BB	2
AA	3
BB	2
CC	3
DD	2
BB	1
BB	0
AA	1
DD	0
AA	1
DD	0
AA	1
DD	0
AA	1
DD	0

Process finished with exit code 0

Version two

To prevent false wake-up, use while to judge

Version three

Using ReentrantLock, the difference is that the condition.await(); and condition.signalAll(); of Condition are used for waiting and awaking;

package com.zbiti.juc;


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

//High cohesion and low coupling, multithreaded operation resource class
//Multithreaded communication judgment / work / notification to prevent false wake-up judgment
public class ProducerConsumerDemo {
    public static void main(String[] args) {
        AirConditon airConditon = new AirConditon();
        new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    airConditon.increament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "AA").start();

        new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    airConditon.decreament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "BB").start();

        new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    airConditon.increament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "CC").start();

        new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    airConditon.decreament();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "DD").start();
    }
}


//Air conditioning resources with plus degree and minus degree functions
class AirConditon {
    int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    void increament() throws Exception {

        lock.lock();
        try {
            //judge
            while (number != 0) {
                condition.await();
            }

            //work
            number++;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //notice
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }


    void decreament() throws Exception {
        lock.lock();
        try {

            //judge
            while (number != 1) {
                condition.await();
            }

            //work
            number--;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //notice
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

}

Result

AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0
CC	1
DD	0

Process finished with exit code 0

Condition notification wakes up a specific thread

Principle of multithreading communication, judgment, work and notification

Use Condition to cooperate with flag bit to inform specific thread to work, and modify flag bit before notification

package com.zbiti.juc;


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

//Three threads a B C, a print 5 times, B print 10 times, C print 15 times, cycle 10 times
public class ConditionDemo {
    public static void main(String[] args) {
        ShareData shareData = new ShareData();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareData.print5();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareData.print10();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareData.print15();
            }
        }, "C").start();
    }


}

//Resource class
class ShareData {
    Lock lock = new ReentrantLock();
    Condition c1 = lock.newCondition();
    Condition c2 = lock.newCondition();
    Condition c3 = lock.newCondition();

    //Flag bit 1 thread A execution, 2 thread B execution, 3 thread C execution
    int number = 1;

    void print5() {
        lock.lock();
        try {
            //judge
            while (number != 1) {
                c1.await();
            }
            //work
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            //Change flag before notification
            number = 2;
            c2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

    void print10() {
        lock.lock();
        try {
            //judge
            while (number != 2) {
                c2.await();
            }
            //work
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            //notice
            number = 3;
            c3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

    void print15() {
        lock.lock();
        try {
            //judge
            while (number != 3) {
                c3.await();
            }
            //work
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            //notice
            number = 1;
            c1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Small summary

Trilogy of inter thread communication, judgment, work, and notification wake-up. In order to prevent false wake-up, while is used for judgment

synchronized version

ReentrantLock version

Condition notifies to wake up a specific thread, and modifies the flag bit before the notification wakes up

This article is based on the platform of blog one article multiple sending OpenWrite Release!

Topics: Programming Java