千家信息网

Java如何实现多线程循环打印

发表于:2025-11-10 作者:千家信息网编辑
千家信息网最后更新 2025年11月10日,这篇文章将为大家详细讲解有关Java如何实现多线程循环打印,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。wait-notify循环打印问题可以通过设置目标值,每个线
千家信息网最后更新 2025年11月10日Java如何实现多线程循环打印

这篇文章将为大家详细讲解有关Java如何实现多线程循环打印,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

wait-notify

循环打印问题可以通过设置目标值,每个线程想打印目标值,如果拿到锁后这次轮到的数不是它想要的就进入wait

class Wait_Notify_ABC {    private int num;    private static final Object Lock = new Object();    private void print_ABC(int target) {        synchronized (Lock) {            //循环打印            for (int i = 0; i < 10; i++) {                while (num % 3 != target) {                    try {                        Lock.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                num++;                System.out.print(Thread.currentThread().getName());                Lock.notifyAll();            }        }    }    public static void main(String[] args) {        Wait_Notify_ABC wait_notify_abc = new Wait_Notify_ABC();        new Thread(() -> {            wait_notify_abc.print_ABC(0);        }, "A").start();        new Thread(() -> {            wait_notify_abc.print_ABC(1);        }, "B").start();        new Thread(() -> {            wait_notify_abc.print_ABC(2);        }, "C").start();    }}

打印1-100问题可以理解为有个全局计数器记录当前打印到了哪个数,其它就和循环打印ABC问题相同。

class Wait_Notify_100 {    private int num;    private static final Object LOCK = new Object();    private int maxnum = 100;    private void printABC(int targetNum) {        while (true) {            synchronized (LOCK) {                while (num % 3 != targetNum) {                    if (num >= maxnum) {                        break;                    }                    try {                        LOCK.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                if (num >= maxnum) {                    break;                }                num++;                System.out.println(Thread.currentThread().getName() + ": " + num);                LOCK.notifyAll();            }        }    }    public static void main(String[] args) {        Wait_Notify_100 wait_notify_100 = new Wait_Notify_100();        new Thread(() -> {            wait_notify_100.printABC(0);        }, "thread1").start();        new Thread(() -> {            wait_notify_100.printABC(1);        }, "thread2").start();        new Thread(() -> {            wait_notify_100.printABC(2);        }, "thread3").start();    }}

join方式

一个线程内调用另一个线程的join()方法可以让另一个线程插队执行,比如Main方法里调用了A.join(),那么此时cpu会去执行A线程中的任务,执行完后再看Main是否能抢到运行权。所以对于ABC,我们可以对B说让A插队,对C说让B插队

class Join_ABC {    static class printABC implements Runnable {        private Thread beforeThread;        public printABC(Thread beforeThread) {            this.beforeThread = beforeThread;        }        @Override        public void run() {            if (beforeThread != null) {                try {                    beforeThread.join();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            System.out.print(Thread.currentThread().getName());        }    }    public static void main(String[] args) throws InterruptedException {        for (int i = 0; i < 10; i++) {            Thread t1 = new Thread(new printABC(null), "A");            Thread t2 = new Thread(new printABC(t1), "B");            Thread t3 = new Thread(new printABC(t2), "C");            t1.start();            t2.start();            t3.start();            Thread.sleep(100);        }    }}

ReentrantLock

同理,synchronized和reentrantlock都是我们常用的加锁方式,不过后者可以中断,可以实现公平锁,可以使用condition…但是需要我们手动释放锁。jdk8后二者性能差不多,毕竟synchronized有锁升级的过程嘛。

class ReentrantLock_ABC {    private int num;       private Lock lock = new ReentrantLock();    private void printABC(int targetNum) {        for (int i = 0; i < 100; ) {            lock.lock();            if (num % 3 == targetNum) {                num++;                i++;                System.out.print(Thread.currentThread().getName());            }            lock.unlock();        }    }    public static void main(String[] args) {        Lock_ABC lockABC = new Lock_ABC();        new Thread(() -> {            lockABC.printABC(0);        }, "A").start();        new Thread(() -> {            lockABC.printABC(1);        }, "B").start();        new Thread(() -> {            lockABC.printABC(2);        }, "C").start();    }}

ReentrantLock+Condition

以上方式如果线程抢到锁后发现自己无法执行任务,那么就释放,然后别的线程再抢占再看是不是自己的…这种方式比较耗时,如果我们能实现精准唤醒锁呢,即A完成任务后唤醒它的下一个即B,这就用到我们的Condition啦

class ReentrantLock_Condition_ABC {    private int num;    private static Lock lock = new ReentrantLock();    private static Condition c1 = lock.newCondition();    private static Condition c2 = lock.newCondition();    private static Condition c3 = lock.newCondition();    private void printABC(int targetNum, Condition currentThread, Condition nextThread) {        for (int i = 0; i < 100; ) {            lock.lock();            try {                while (num % 3 != targetNum) {                    currentThread.await();  //阻塞当前线程                }                num++;                i++;                System.out.print(Thread.currentThread().getName());                nextThread.signal();    //唤醒下一个线程            } catch (Exception e) {                e.printStackTrace();            } finally {                lock.unlock();            }        }    }    public static void main(String[] args) {        ReentrantLock_Condition_ABC reentrantLockConditionAbc = new ReentrantLock_Condition_ABC();        new Thread(() -> {            reentrantLockConditionAbc.printABC(0, c1, c2);        }, "A").start();        new Thread(() -> {            reentrantLockConditionAbc.printABC(1, c2, c3);        }, "B").start();        new Thread(() -> {            reentrantLockConditionAbc.printABC(2, c3, c1);        }, "C").start();    }}

Semaphore

小伙伴们有没有想到过,在生产者消费者模型中我们有哪几种实现方式呢?wait\notify,ReentrantLock,Semaphone,阻塞队列,管道输入输出流。
对的就是Semaphone。
Semaphore有acquire方法和release方法。 当调用acquire方法时线程就会被阻塞,直到获得许可证为止。 当调用release方法时将向Semaphore中添加一个许可证。如果没有获取许可证的线程, Semaphore只是记录许可证的可用数量。
使用Semaphore也可以实现精准唤醒。

class SemaphoreABC {    private static Semaphore s1 = new Semaphore(1); //因为先执行线程A,所以这里设s1的计数器为1    private static Semaphore s2 = new Semaphore(0);    private static Semaphore s3 = new Semaphore(0);    private void printABC(Semaphore currentThread, Semaphore nextThread) {        for (int i = 0; i < 10; i++) {            try {                currentThread.acquire();       //阻塞当前线程,即信号量的计数器减1为0                System.out.print(Thread.currentThread().getName());                nextThread.release();          //唤醒下一个线程,即信号量的计数器加1            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) throws InterruptedException {        SemaphoreABC printer = new SemaphoreABC();        new Thread(() -> {            printer.printABC(s1, s2);        }, "A").start();        Thread.sleep(100);        new Thread(() -> {            printer.printABC(s2, s3);        }, "B").start();        Thread.sleep(100);        new Thread(() -> {            printer.printABC(s3, s1);        }, "C").start();    }}

关于"Java如何实现多线程循环打印"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

线程 方法 循环 方式 许可证 任务 篇文章 问题 精准 更多 目标 目标值 计数器 阻塞 不错 实用 相同 差不多 产者 全局 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 中国引文数据库的收录范围 软件开发专业找什么工作好 服务器装安全狗很慢 魔兽无法刷新服务器列表 工业级视频会议服务器 xp打开管理服务器不可用 可以只包括一种服务器 网很好为什么连接不上服务器 上海酷丹网络技术有限公司 服务器管理器在哪里找 邹平采购软件开发价格 云大网络技术与应用期末题 网络安全销售投标案例演练 数据库恢复 oracle 手机软件开发收益 sd卡视频文件恢复数据库 AI智能就是软件开发是吗 光伏电站网络安全专职负责人 利用网络技术开展农民教育培训 网络安全可以线下学吗 基于数据库的编程技术 网络安全备份和恢复 数据库的容灭属于系统安全 考试系统软件开发 七彩网络安全技术有限公司 数据库设置安全区域 网络安全标志有哪些 修改数据库中表的编码格式 云服务器云磁盘 筑客网络技术上海公司荣誉
0