使用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. 观察者模式的应用:Winform窗体之间传值

    观察者模式的应用:Winform窗体传值 观察者模式的概念: 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并更新. 今天我们就学着用一下这个观察者模式,先想象 ...

  2. shell学习-常用语句

    为什么使用shell 可以快速.简单的完成编程,实现自己的想法.Shell非常适合编写小的工具,因为小工具更强调的是易于配置.维护.移植等,而不是执行效率. 当自己的想法确实有必要进行优化,有必要让它 ...

  3. 3maven常用命令和配置依赖

    依赖: 例:spring-context.jar 依赖 spring-aop.jar... A中的某些类 需要使用B中的某些类,则称为A依赖于B 在maven项目中,如果要使用 一个当时存在的Jar或 ...

  4. TensorFlow——LinearRegression简单模型代码

    代码函数详解 tf.random.truncated_normal()函数 tf.truncated_normal函数随机生成正态分布的数据,生成的数据是截断的正态分布,截断的标准是2倍的stddev ...

  5. js正则定义支付宝账号、手机号、邮箱

    一.支付宝账号:可以只输入数字.字母.字母(数字)+数字(字母),其中只字母中可以含有@._或者.也可以三者都可以包含并且可以在任意位置,限制:小于等于30位(可根据需求自定义范围): let  zh ...

  6. Git高级之配置多个SSH key

    最近我们在代码托管平台上使用SSH的方式下拉代码,通常是用一个ssh key来拉取所有托管平台的代码,如码云,GitHub.GitLab等,但是总用一个不是太好.会有安全风险,这就需要为每个托管平台设 ...

  7. Nginx代理服务——正向代理

    正向代理 在/opt/app/code的目录下创建一个joy.html文件 <html> <head> <meta charset="utf-8"&g ...

  8. python 文件监听

    对文件进行监听.过滤 def tail(filename): f = open(file=filename, mode='r', encoding='utf-8') # 打开文件不能用with,因为监 ...

  9. Flash 上下文管理

    1.Local() 作用:为每个协程或线程创建一个独立的内存空间 储存格式: { 唯一标识: {'stack': []} } 代码 try: from greenlet import getcurre ...

  10. 缓存读写策略 - Cache Aside.md

    场景描述 比如一条数据同时存在数据库.缓存,现在你要更新此数据,你会怎么更新? 先更新数据库?还是先更新缓存? 其实这两种方式都有问题. (1)先更新数据库,后更新缓存 这样会造成数据不一致. A 先 ...