[Java SDK] [多线程] Java中线程的定制化通信

简介: [Java SDK] [多线程] Java中线程的定制化通信

简介

线程的定制化通信:顾名思义多线程的循环交替执行。 有一个很经典的案例如下:
三个线程之间按顺序调用,实现 A -> B -> C 三个线程启动,要求如下:

AA打印5次,BB打印10次,CC打印15次
 接着

AA 打印5次,BB打印10次,CC打印15次
……
循环10轮

大致通过JDK的支持梳理了下面的几种方案

  1. 通过线程不加锁定义状态变量(sleep)
  2. 通过synchronized关键字, 结合的wait与notifyAll
  3. Lock接口中 通过ReentrantLock的lock以及unlock
  4. Lock接口中 ReentrantLock结合Condition
  5. Lock接口中 Semaphore信号量方式

方法 / 步骤

一:通过线程不加锁定义状态变量(sleep)

通过线程配合sleep不加锁定义状态变量(非线程安全,可能会少打印)
启动三个线程,按照如下要求:
AA打印5此,BB打印10次,CC打印15次,一共进行10轮

public class ThreadOfSleep {

    private static String message = "AA";
    private static Integer loop = 1;

    public void TdSleep() {
        new Thread(() -> {
            int count = 1;
            while (count <= 5) {
                while (!message.equals("AA")) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(message);
                count = count + 1;
            }
            //while end
            message = "BB";
        }, "AA").start();

        new Thread(() -> {
            int count = 1;

                while (count <= 10) {
                    while (!message.equals("BB")) {
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //while end
                    System.out.println(message);
                    count = count + 1;

                }
                message = "CC";

        }, "BB").start();


        new Thread(() -> {
            int count = 1;
                while (count <= 15) {
                    while (!message.equals("CC")) {
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //while end
                    System.out.println(message);
                    count = count + 1;
                }
                message = "AA";
//                loop+=1;
//                System.out.println("current loop: "+ loop);

        }, "CC").start();

    }


    static class ThreadOfSleepTest {

        public static void main(String[] args) {
            ThreadOfSleep threadOfSleep = new ThreadOfSleep();
            for (int i = 1; i <= 10; i++) {
                threadOfSleep.TdSleep();
            }
        }
    }

二:通过synchronized关键字, 结合的wait与notifyAll

通过synchronized锁定 对象标志位的 wait与 notifyAll 定制线程间的通信
启动三个线程,按照如下要求:AA打印5次,BB打印10次,CC打印15次,一共进行10轮

public class ThreadOfSynchronized {


    private static String message = "AA";
    private static Integer loop = 1;
    private static Object lock = new Object();

    public void ThreadOfSync() {
        new Thread(() -> {
            int count = 1;

            synchronized (lock) {
                while (count <= 5) {
                    while (!message.equals("AA")) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(message);
                    count = count + 1;
                }
                //while end
                message = "BB";
                lock.notifyAll();
            }
            //sync end

        }, "AA").start();

        new Thread(() -> {
            int count = 1;

            synchronized (lock) {
                while (count <= 10) {
                    while (!message.equals("BB")) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //while end
                    System.out.println(message);
                    count = count + 1;

                }
                message = "CC";
                lock.notifyAll();
            }
            //sync end
        }, "BB").start();


        new Thread(() -> {
            int count = 1;
            synchronized (lock) {
                while (count <= 15) {
                    while (!message.equals("CC")) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //while end
                    System.out.println(message);
                    count = count + 1;
                }
                message = "AA";
                loop+=1;
                System.out.println("current loop: "+ loop);
                lock.notifyAll();
            }
            //sync end
        }, "CC").start();
    }


    public static class ThreadOfSynchronizedTest {
        public static void main(String[] args) {
            ThreadOfSynchronized threadOfSynchronized = new ThreadOfSynchronized();
            for (int i = 1; i <= 10; i++) {
                threadOfSynchronized.ThreadOfSync();
            }
        }
    }

}

三:通过ReentrantLock的lock以及unlock

通过ReentrantLock的lock以及unlock 进行定制线程
交替打印AA BB CC 十次 通过前面的线程 循环带出后面线程

public class ThreadOfRLock {

    // 通过JDK5中的Lock锁来保证线程的访问的互斥
    static Lock rLock = new ReentrantLock();
    //通过state的值来确定是否打印
    private static int state = 1;

    static class ThreadA extends Thread {
        @Override
        public void run() {
            for (int i = 1; i <= 10;) {
                try {
                    rLock.lock();
                    // 多线程并发,不能用if,必须用循环测试等待条件,避免虚假唤醒
                    while (state % 3 == 1) {
                        System.out.println(Thread.currentThread().getName()+"->> AA");
                        state++;
                        i++;
                    }
                } finally {
                    rLock.unlock();
                }
            }
        }
    }
    static class ThreadB extends Thread {
        @Override
        public void run() {
            for (int i = 1; i <= 10;) {
                try {
                    rLock.lock();
                    while (state % 3 == 2) {
                        System.out.println(Thread.currentThread().getName()+"->> BB");
                        state++;
                        i++;
                    }
                } finally {
                    rLock.unlock();
                }
            }
        }
    }
    static class ThreadC extends Thread {
        @Override
        public void run() {
            for (int i = 1; i <= 10;) {
                try {
                    rLock.lock();
                    while (state % 3 == 0) {
                        System.out.println(Thread.currentThread().getName()+"->> CC");
                        state++;
                        i++;

                    }
                } finally {
                    rLock.unlock();
                }
            }
        }
    }
    public static void main(String[] args) {
        new ThreadA().start();
        new ThreadB().start();
        new ThreadC().start();
    }

}

四:ReentrantLock结合Condition

启动三个线程,按照如下要求:
AA打印5此,BB打印10次,CC打印15次,一共进行10轮
每个线程添加一个标志位,是该标志位则执行操作,并且修改为下一个标志位,通知下一个标志位的线程
创建一个可重入锁private Lock lock = new ReentrantLock();
分别创建三个开锁通知private Condition c1 = lock.newCondition();
通过标志位Flag 和Condition 的wait 当前线程, sign(钥匙) 唤醒下一个线程 进行交替打印
public class CustomThread {

    //定义标志位
    private int flag = 1;

    //创建Lock锁
    Lock rLock = new ReentrantLock();

    //创建3个Condition 环境条件(Condition是绑定当前线程的)
    Condition c1 = rLock.newCondition();
    Condition c2 = rLock.newCondition();
    Condition c3 = rLock.newCondition();

    //打印5次,loop表示第几轮
    public void print5Count(int loop) throws InterruptedException {
        //上锁
        rLock.lock();
        try {
            //打印5次的标志位为1 打印10次标志位为2 打印15次的标志位为3, 非本次条件为等待
            while (flag != 1) {
                c1.await();
            }
            //业务处理
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "::" + i + ": 轮数:" + loop);
            }
            //通知 修改标志位2
            flag = 2;
            //
            c2.signal();
        } finally {
            //释放锁
            rLock.unlock();
        }
    }

    //打印10次,loop表示第几轮
    public void print10Count(int loop) throws InterruptedException {
        //上锁
        rLock.lock();
        try {
            //打印5次的标志位为1 打印10次标志位为2 打印15次的标志位为3, 非本次条件为等待
            while (flag != 2) {
                c2.await();
            }
            //业务处理
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "::" + i + ": 轮数:" + loop);
            }
            //通知 修改标志位2
            flag = 3;
            c3.signal();
        } finally {
            //释放锁
            rLock.unlock();
        }
    }


    //打印5次,loop表示第几轮
    public void print15Count(int loop) throws InterruptedException {
        //上锁
        rLock.lock();
        try {
            //打印5次的标志位为1 打印10次标志位为2 打印15次的标志位为3, 非本次条件为等待
            while (flag != 3) {
                c3.await();
            }
            //业务处理
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "::" + i + ": 轮数:" + loop);
            }
            //通知 标志位为1的
            flag = 1;
            c1.signal();
        } finally {
            //释放锁
            rLock.unlock();
        }
    }

    public static class CustomThreadTest {

        public static void main(String[] args) {
            CustomThread customThread = new CustomThread();

            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        customThread.print5Count(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "AA").start();

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


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


}

五:Semaphore信号量方式

定义的全局变量,使用static
通过static Semaphore A = new Semaphore(1);,代表信号量为1
具体其代码块为:
semaphore.acquire(); 获取信号量
semaphore.release();释放信号量
public class ThreadOfSemaphore {


    // 以A开始的信号量,初始信号量数量为1
    private static Semaphore A = new Semaphore(1);
    // B、C信号量,A完成后开始,初始信号数量为0
    private static Semaphore B = new Semaphore(0);
    private static Semaphore C = new Semaphore(0);

    static class ThreadA extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 1; i <= 10; i++) {
                    A.acquire();// A获取信号执行,A信号量减1,当A为0时将无法继续获得该信号量
                    System.out.println("AA");
                    B.release();// B释放信号,B信号量加1(初始为0),此时可以获取B信号量
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class ThreadB extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 1; i <= 10; i++) {
                    B.acquire();
                    System.out.println("BB");
                    C.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class ThreadC extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 1; i <= 10; i++) {
                    C.acquire();
                    System.out.println("CC");
                    A.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public static void main(String[] args) {
        new ThreadA().start();
        new ThreadB().start();
        new ThreadC().start();
    }

}

参考资料 & 致谢

目录
相关文章
|
10天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
27 2
|
3天前
|
Java 数据库 UED
Java的多线程有什么用
Java的多线程技术广泛应用于提升程序性能和用户体验,具体包括:提高性能,通过并行执行充分利用多核CPU;保持响应性,使用户界面在执行耗时操作时仍流畅交互;资源共享,多个线程共享同一内存空间以协同工作;并发处理,高效管理多个客户端请求;定时任务,利用`ScheduledExecutorService`实现周期性操作;任务分解,将大任务拆分以加速计算。多线程尤其适用于高并发和并行处理场景。
|
14天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理
|
16天前
|
Java 开发者
Java中的多线程基础与应用
【9月更文挑战第22天】在Java的世界中,多线程是一块基石,它支撑着现代并发编程的大厦。本文将深入浅出地介绍Java中多线程的基本概念、创建方法以及常见的应用场景,帮助读者理解并掌握这一核心技术。
|
12天前
|
Java 调度
Java-Thread多线程的使用
这篇文章介绍了Java中Thread类多线程的创建、使用、生命周期、状态以及线程同步和死锁的概念和处理方法。
Java-Thread多线程的使用
|
15天前
|
Java 调度 开发者
Java中的多线程编程:从基础到实践
本文旨在深入探讨Java多线程编程的核心概念和实际应用,通过浅显易懂的语言解释多线程的基本原理,并结合实例展示如何在Java中创建、控制和管理线程。我们将从简单的线程创建开始,逐步深入到线程同步、通信以及死锁问题的解决方案,最终通过具体的代码示例来加深理解。无论您是Java初学者还是希望提升多线程编程技能的开发者,本文都将为您提供有价值的见解和实用的技巧。
15 2
|
10天前
|
Java 数据中心 微服务
Java高级知识:线程池隔离与信号量隔离的实战应用
在Java并发编程中,线程池隔离与信号量隔离是两种常用的资源隔离技术,它们在提高系统稳定性、防止系统过载方面发挥着重要作用。
10 0
|
12天前
|
Java 数据处理 调度
Java中的多线程编程:从基础到实践
本文深入探讨了Java中多线程编程的基本概念、实现方式及其在实际项目中的应用。首先,我们将了解什么是线程以及为何需要多线程编程。接着,文章将详细介绍如何在Java中创建和管理线程,包括继承Thread类、实现Runnable接口以及使用Executor框架等方法。此外,我们还将讨论线程同步和通信的问题,如互斥锁、信号量、条件变量等。最后,通过具体的示例展示了如何在实际项目中有效地利用多线程提高程序的性能和响应能力。
|
13天前
|
传感器 网络协议 Java
三大硬核方式揭秘:Java如何与底层硬件和工业设备轻松通信!
大家好,我是V哥。最近与一位从事工业互联网项目的学员交流,启发我分享Java如何与底层硬件和工业设备通信。本文将介绍三种方法:1)使用`jLibModbus`库通过Modbus协议读取设备寄存器数据;2)使用JNI(Java Native Interface)直接访问硬件;3)使用`JSerialComm`库通过串口通信读取数据。每种方法都有详细步骤和示例代码,帮助你轻松实现与硬件设备的通信。无论是工业自动化还是物联网应用,这些方法都能派上用场。欢迎关注和支持!
|
13天前
|
安全 算法 Java
Java中的多线程编程:从基础到高级应用
本文深入探讨了Java中的多线程编程,从最基础的概念入手,逐步引导读者了解并掌握多线程开发的核心技术。无论是初学者还是有一定经验的开发者,都能从中获益。通过实例和代码示例,本文详细讲解了线程的创建与管理、同步与锁机制、线程间通信以及高级并发工具等主题。此外,还讨论了多线程编程中常见的问题及其解决方案,帮助读者编写出高效、安全的多线程应用程序。

热门文章

最新文章