使用Java实现三个线程交替打印0-74

题目分析

 三个线程交替打印,即3个线程是按顺序执行的。一个线程执行完之后,唤醒下一个线程,然后阻塞,等待被该线程的上一个线程唤醒。执行的顺序是一个环装的队列 0->1->2->0 ....->0->1->2

实现思路

  由于三个线程一次只能有一个在打印数字,所以需要用一个锁来进行同步。但是在打印时要保证顺序就要求 一个线程打印完之后只能唤醒它的下一个线程,而不是唤醒所有的线程。这就要求给每一个线程都有一个自己的状态来控制阻塞和唤醒。
java 并发包中的锁(实现了Lock接口的ReentrantLock、ReentrantReadWriteLock)有一个newCondition方法。调用该方法会返回与该锁绑定Condition对象实例。当线程获取锁之后,调用Condition实例的await方法会自动释放线程的锁,当其他线程调用该Condition对象实例的signal方法后,该线程会自动尝试获取锁。
通过对Condition的分析可知,我们只要对三个线程生成三个Condition对象。当一个线程打印一个数字之后就调用下一个线程的Condition对象的signal方法唤醒下一个线程,然后调用自己的Condition的await线程进入等待状态。这样就实现了线程执行顺序的控制。由于线程的执行是一个环形的队列,我们用一个数组存放每个线程的Condition对象,通过对下标加一然后取模来实现环形队列。

代码

package com.test.concurrent.alternatingprint;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; public class PrintNumber extends Thread {
/**
* 多个线程共享这一个sequence数据
*/
private static int sequence=0; private static final int SEQUENCE_END =75; private Integer id;
private ReentrantLock lock;
private Condition[] conditions; private PrintNumber(Integer id, ReentrantLock lock, Condition[] conditions) {
this.id = id;
this.setName("thread" + id);
this.lock = lock;
this.conditions = conditions;
} @Override
public void run() {
while (sequence >= 0 && sequence < SEQUENCE_END) {
lock.lock();
try {
//对序号取模,如果不等于当前线程的id,则先唤醒其他线程,然后当前线程进入等待状态
while (sequence % conditions.length != id) {
conditions[(id + 1) % conditions.length].signal();
conditions[id].await();
}
System.out.println(Thread.currentThread().getName() + " " + sequence);
//序号加1
sequence = sequence + 1;
//唤醒当前线程的下一个线程
conditions[(id + 1) % conditions.length].signal();
//当前线程进入等待状态
conditions[id].await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//将释放锁的操作放到finally代码块中,保证锁一定会释放
lock.unlock();
}
}
//数字打印完毕,线程结束前唤醒其余的线程,让其他线程也可以结束
end();
} private void end() {
lock.lock();
conditions[(id + 1) % conditions.length].signal();
conditions[(id + 2) % conditions.length].signal();
lock.unlock();
} public static void main(String[] args) {
int threadCount = 3;
ReentrantLock lock = new ReentrantLock();
Condition[] conditions = new Condition[threadCount];
for (int i = 0; i < threadCount; i++) {
conditions[i] = lock.newCondition();
}
PrintNumber[] printNumbers = new PrintNumber[threadCount];
for (int i = 0; i < threadCount; i++) {
PrintNumber p = new PrintNumber(i, lock, conditions);
printNumbers[i] = p;
}
for (PrintNumber printNumber : printNumbers) {
printNumber.start();
}
} }

使用Java实现三个线程交替打印0-74的更多相关文章

  1. 多线程下,两个线程交替打印0 -100,使用wait()和notify()

    多线程下,两个线程交替打印0 -100,使用wait()和notify() public class ThreadTest{ private static final Object lock = ne ...

  2. 使用Java线程并发库实现两个线程交替打印的线程题

    背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一个多线程的问题.晚上闲着没事就决定把它实现出来. 题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交 ...

  3. Java中多个线程交替循环执行

    有些时候面试官经常会问,两个线程怎么交替执行呀,如果是三个线程,又怎么交替执行呀,这种问题一般人还真不一定能回答上来.多线程这块如果理解的不好,学起来是很吃力的,更别说面试了.下面我们就来剖析一下怎么 ...

  4. Java并发 两个线程交替执行和死锁

    今天看到一个题:两个线程交替打印奇数和偶数,即一个线程打印奇数,另一个打印偶数,交替打印从1到100.想了下有多重实现方法. wait和notify方法: public class OddEven { ...

  5. java实现线程交替打印1-52和A-Z

    题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交替打印,输出结果为12A34B...........5152Z. 3.请用多线程方式实现. 实现思路:通过锁(s ...

  6. 斐讯面试记录—三线程交替打印ABC

    package cn.shenzhen.feixun; public class PrintABC extends Thread{ private String name; private Objec ...

  7. java Semaphore实现ABC三个线程循环打印

    Semaphore位于java.util.concurrent包下.其中有两个重要的方法acquire()和release().acquire用来获取一个信号量,并且是阻塞型的,如果当前还有可用的信号 ...

  8. java启动3个线程轮流打印数字

    转自:http://blog.csdn.net/u014011112/article/details/50988769 http://blog.csdn.net/perrywork/article/d ...

  9. java多线程三之线程协作与通信实例

    多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...

随机推荐

  1. MySQL故障演习

    MySQL故障演习 接上次的 MySQL定时备份 该次实验主要是练习在MySQL数据库发生误删等意外情况下,利用全量备份文件和增量备份文件恢复数据. 1. 实验环境 -- 创建数据库 create d ...

  2. Kettle中JavaScript内置函数说明

    本文链接:https://blog.csdn.net/u010192145/article/details/102220563 我们在使用JavaScript组件的时候,在左侧核心树对象栏中可以看到K ...

  3. [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause报错问题的解决

    run SQL: select version(),@@sql_mode;SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','' ...

  4. nacos-docker安装nacos并配置数据库

    拉取nacos/nacos-server镜像 docker pull nacos/nacos-server 配置数据库(MySQL) 创建存储nacos配置的数据库 create database n ...

  5. Spark读写ES

    本文主要介绍spark sql读写es.structured streaming写入es以及一些参数的配置 ES官方提供了对spark的支持,可以直接通过spark读写es,具体可以参考ES Spar ...

  6. 网络流入门题目 - bzoj 1001

    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点 ...

  7. 《利用python进行数据分析》——Numpy基础

    一.创建数组 1.创建数组的函数 array:将输入数据(列表.元组.数组或其他序列类型)转换为ndarray,可用dtype指定数据类型. >>> import numpy as ...

  8. python 注册登录(文件操作)

    name = input("请注册用户:") password = input("请注册密码:") with open(file="user" ...

  9. 清晰架构(Clean Architecture)的Go微服务: 事物管理

    为了支持业务层中的事务,我试图在Go中查找类似Spring的声明式事务管理,但是没找到,所以我决定自己写一个. 事务很容易在Go中实现,但很难做到正确地实现. 需求: 将业务逻辑与事务代码分开. 在编 ...

  10. 玩转Django2.0---Django笔记建站基础十一(二)((音乐网站开发))

    11.5 歌曲排行榜 歌曲排行榜是通过首页的导航链接进入的,按照歌曲的播放次数进行降序显示.从排行榜页面的设计图可以看到,网页实现三个功能:网页顶部搜索.歌曲分类筛选和歌曲信息列表,其说明如下: 1. ...