使用Java实现三个线程交替打印0-74
使用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的更多相关文章
- 多线程下,两个线程交替打印0 -100,使用wait()和notify()
多线程下,两个线程交替打印0 -100,使用wait()和notify() public class ThreadTest{ private static final Object lock = ne ...
- 使用Java线程并发库实现两个线程交替打印的线程题
背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一个多线程的问题.晚上闲着没事就决定把它实现出来. 题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交 ...
- Java中多个线程交替循环执行
有些时候面试官经常会问,两个线程怎么交替执行呀,如果是三个线程,又怎么交替执行呀,这种问题一般人还真不一定能回答上来.多线程这块如果理解的不好,学起来是很吃力的,更别说面试了.下面我们就来剖析一下怎么 ...
- Java并发 两个线程交替执行和死锁
今天看到一个题:两个线程交替打印奇数和偶数,即一个线程打印奇数,另一个打印偶数,交替打印从1到100.想了下有多重实现方法. wait和notify方法: public class OddEven { ...
- java实现线程交替打印1-52和A-Z
题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交替打印,输出结果为12A34B...........5152Z. 3.请用多线程方式实现. 实现思路:通过锁(s ...
- 斐讯面试记录—三线程交替打印ABC
package cn.shenzhen.feixun; public class PrintABC extends Thread{ private String name; private Objec ...
- java Semaphore实现ABC三个线程循环打印
Semaphore位于java.util.concurrent包下.其中有两个重要的方法acquire()和release().acquire用来获取一个信号量,并且是阻塞型的,如果当前还有可用的信号 ...
- java启动3个线程轮流打印数字
转自:http://blog.csdn.net/u014011112/article/details/50988769 http://blog.csdn.net/perrywork/article/d ...
- java多线程三之线程协作与通信实例
多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...
随机推荐
- 使用SqlDependency实时监听SQL server数据库变化并执行事件
sql server设置:ALTER DATABASE <DatabaseName> SET ENABLE_BROKER;语句让相应的数据库启用监听服务,以便支持SqlDependency ...
- Mybatis中jdbcType的类型
具体支持的类型参见:org.apache.ibatis.type.JdbcType ARRAY, BIT, TINYINT, SMALLINT, INTEGER, BIGINT, FLOAT, REA ...
- 20190918Java课堂记录
1. EnumTest.java public class EnumTest { public static void main(String[] args) { Size s=Size.SMALL; ...
- 去除Linux中的^M
(1)安装tofrodos sudo apt-get install tofrodos (2)做一些优化 ln -s /usr/bin/todos /usr/bin/unix2dos ln -s /u ...
- Django admin的常用方法
一.HTTP 1.主页面 http://127.0.0.1:8000/admin/ 2.查询页面 http://127.0.0.1:8000/admin/app01/book/ 3.增加页面 http ...
- Java入门 - 导读
原文地址:http://www.work100.net/training/java 更多教程:光束云 - 免费课程 Java入门 Java 是由 Sun Microsystems 公司于1995年5月 ...
- Entity Framework 6+ 连接Mysql
好吧.这个博客开不开的 我感觉.. 都一样了. 前言: 公司改造Sqlserver ->Mysql Sql2016老夫对不住你啊.. 好 前沿结束. 需要的家伙: 1.mysql-for-vis ...
- nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.报错解决
近期在学springboot,学的时候遇到这个错,网上查了好多,改了不行,后来发现自己的配置类没有加@SpringBootApplication注解 Exception encountered dur ...
- 【java面试】线程篇
1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位. 2.线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任 ...
- linux ftp 服务器 ,web 服务器 配置
ftp服务器配置: 1:vsftpd.conf 2;vsftpd.ftpusers 3:vsftpd.user_list web服务器配置: apache 配置