Java:现有线程T1/T2/T3,如何确保T1执行完成之后执行T2,T3在T2执行完成之后执行。
要实现多个线程执行完成先后,就要知道如何实现线程之间的等待,java线程等待实现是join。java的jdk中join方法实现如下:
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0; if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
} if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
实现需求的方案一:
public class TestMain {
public static void main(String[] args) throws InterruptedException {
Thread T1 = new MyThread("T1");
Thread T2 = new MyThread("T2");
Thread T3 = new MyThread("T3");
System.out.println("T1 start.");
T1.start();
T1.join();
System.out.println("T1 complete.");
System.out.println("T2 start.");
T2.start();
T2.join();
System.out.println("T2 complete.");
System.out.println("T3 start.");
T3.start();
T3.join();
System.out.println("T3 complete.");
}
}
class MyThread extends Thread {
public MyThread(String name) {
setName(name);
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
// do something...
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
实现需求的方案二:
public class Test2Main {
public static void main(String[] args) {
final Thread T1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("T1...");
}
});
final Thread T2 = new Thread(new Runnable() {
@Override
public void run() {
try {
T1.join();
}catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("T2...");
}
});
final Thread T3 = new Thread(new Runnable() {
@Override
public void run() {
try {
T2.join();
}catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("T3...");
}
});
T3.start();
T2.start();
T1.start();
}
}
实现方案三:使用ReentrantLock来解决, 还有个state整数用来判断轮到谁执行了
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ABC {
private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥
private static int state = 0; static class ThreadA extends Thread {
@Override
public void run() {
for (int i = 0; i < 10;) {
lock.lock();
if (state % 3 == 0) {
System.out.print("A");
state++;
i++;
}
lock.unlock();
}
}
} static class ThreadB extends Thread {
@Override
public void run() {
for (int i = 0; i < 10;) {
lock.lock();
if (state % 3 == 1) {
System.out.print("B");
state++;
i++;
}
lock.unlock();
}
}
} static class ThreadC extends Thread {
@Override
public void run() {
for (int i = 0; i < 10;) {
lock.lock();
if (state % 3 == 2) {
System.out.print("C");
state++;
i++;
}
lock.unlock();
}
}
} public static void main(String[] args) {
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
} }
使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 思路简单
实现方案四:还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ABC2 {
private static Lock lock = new ReentrantLock();
private static int count = 0;
private static Condition A = lock.newCondition();
private static Condition B = lock.newCondition();
private static Condition C = lock.newCondition(); static class ThreadA extends Thread { @Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (count % 3 != 0)
A.await(); // 会释放lock锁
System.out.print("A");
count++;
B.signal(); // 唤醒相应线程
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} } static class ThreadB extends Thread { @Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (count % 3 != 1)
B.await();
System.out.print("B");
count++;
C.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} } static class ThreadC extends Thread { @Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (count % 3 != 2)
C.await();
System.out.println("C");
count++;
A.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} } public static void main(String[] args) throws InterruptedException {
new ThreadA().start();
new ThreadB().start();
ThreadC threadC = new ThreadC();
threadC.start();
threadC.join();
System.out.println(count);
}
}
实现方案五:使用信号量也可以, 这个思路最简单, 整个代码也比较简洁
import java.util.concurrent.Semaphore;
public class ABC3 {
private static Semaphore A = new Semaphore(1);
private static Semaphore B = new Semaphore(1);
private static Semaphore C = new Semaphore(1);
static class ThreadA extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
A.acquire();
System.out.print("A");
B.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadB extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
B.acquire();
System.out.print("B");
C.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadC extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
C.acquire();
System.out.println("C");
A.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
B.acquire(); C.acquire(); // 开始只有A可以获取, BC都不可以获取, 保证了A最先执行
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}
}
注意:
lock是需要lock所有者去释放的, 即谁lock, 谁释放, 不可以跨线程, 会报java.lang.IllegalMonitorStateException;
semaphore是没有所有者的说法, 可以跨线程释放和获取.
方案三、四、五转自《[Java多线程]ABC三个线程顺序输出的问题》
Java:现有线程T1/T2/T3,如何确保T1执行完成之后执行T2,T3在T2执行完成之后执行。的更多相关文章
- Java-JUC(零):Java:现有线程T1/T2/T3,如何确保T1执行完成之后执行T2,T3在T2执行完成之后执行。
要实现多个线程执行完成先后,就要知道如何实现线程之间的等待,java线程等待实现是join.java的jdk中join方法实现如下: public final synchronized void jo ...
- T2 Func<in T1,out T2>(T1 arg)
委托调用方法的4种方式. using System; using System.Collections.Generic; namespace ConsoleApplication1 { delegat ...
- Java多线程--线程安全问题的相关研究
在刚刚学线程的时候我们经常会碰到这么一个问题:模拟火车站售票窗口售票.代码如下: package cn.blogs.com.isole; /* 模拟火车站售票窗口售票,假设有50张余票 */ publ ...
- Java多线程——线程范围内共享变量
多个线程访问共享对象和数据的方式 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. package java_ ...
- java 多线程—— 线程等待与唤醒
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- java进程/线程;堆和栈;多线程
一.进程和线程 进程:在内存中运行的应用程序,一个exe是一个进程. 如:ps -exf 可以查看各个应用的进程,其中ppid为父进程: ps aux | egrep '(cron|syslog)' ...
- Java面向对象 线程技术 -- 下篇
Java面向对象 线程技术 -- 下篇 知识概要: (1)线程间的通信 生产者 - 消费者 (2)生产者消费者案例优化 (3)守护线程 (4)停止线 ...
- Java面向对象 线程技术--上篇
Java面向对象 线程 知识概要: (1)线程与进程 (2)自定义线程的语法结构 (3)多线程概念理解 (4)多线程状态图 (5)多线程--卖票 (6)同 ...
- Java基础——线程
一. 进程 是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程. 比如在Windows系统中,一个运行的exe就是一个进程. 二.线程 是指进程中的一个执行流 ...
随机推荐
- 什么是IPFS?(一)
写在前面: 今天先写到这里, 关于IPFS的所有事情小编都想快点告诉大家, 但毕竟精力有限, 小编尽量抽出时间提供更多的关于IPFS的信息. ----------------------------- ...
- 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇
Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...
- maven依赖大全
1.oracle mysql驱动 <!-- mysql驱动支持 --> <dependency> <groupId>mysql</groupId> &l ...
- const 相关知识 const和指针、const和引用
以前老是对const概念不清不楚,今天算是好好做个笔记总结一下.以下内容包括1)常量指针(指针本身是常量),2)指针常量(指针指向的是常量对象),3)常量引用,4)const成员函数. 常量指针,指针 ...
- python基础学习一 字符串的相关操作
python的字符串 在python中,字符串是以unicode编码的,所以python的字符串支持多语言 对于单个字符的编码,python提供了ord()函数获取字符的整数表示,chr()函数是把编 ...
- 在用jQuery时遇到的小问题
1. class类名问题? 在我在class ='看看(2)' ,凡是这样的居然给自身加其他style样式,居然添加不上,后来改成其他类名不带括号里的,居然好了. 2. line-height 引入的 ...
- 网络通信 --> TCP三次握手和四次挥手
TCP三次握手和四次挥手 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 一.TCP报文格式 如下图: (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发 ...
- 解决办法:由于oracle版本不同导致导入数据时失败
在向一个数据库导入dmp文件时,出现了如下错误 经查询,是由于"导出的dmp文件与导入的数据库的版本不同造成的" 用notepad查看dmp文件的版本,看看是否和数据库版本一致 解 ...
- Beta No.2
今天遇到的困难: 组员对github极度的不适应 Android Studio版本不一致项目难以打开运行 移植云端的时候,愚蠢的把所有项目开发环境全部搬上去.本身云的内存小,性能差,我们花费了太多时间 ...
- Welcome to StackEdit!
Welcome to StackEdit! Hey!our first Markdown document in StackEdit1. Don't delete me, I'm very helpf ...