Java多线程:用三个线程控制循环输出10次ABC
来源:互联网 发布:响应式瀑布流 js插件 编辑:程序博客网 时间:2024/06/03 13:16
题目:有A,B,C三个线程, A线程输出A, B线程输出B, C线程输出C,要求, 同时启动三个线程, 按顺序输出ABC, 循环10次。
解题思路:要按顺序输出ABC, 循环10次,就要控制三个线程同步工作,也就是说要让三个线程轮流输出,直到10个ABC全部输出则结束线程。这里用一个Lock对象来控制三个线程的同步。用一个int型变量state标识由那个线程输出。
package com.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ABC { private static int state = 0; public static void main(String[] args) { final Lock l = new ReentrantLock(); Thread A = new Thread(new Runnable(){ @Override public void run() { while (state<=30) { l.lock(); if(state%3==0){ System.out.println("A"); state ++; } l.unlock(); } } }); Thread B = new Thread(new Runnable(){ @Override public void run() { while (state<=30) { l.lock(); if(state%3==1){ System.out.println("B"); state ++; } l.unlock(); } } }); Thread C = new Thread(new Runnable(){ @Override public void run() { while (state<=30) { l.lock(); if(state%3==2){ System.out.println("C"); state ++; } l.unlock(); } } }); A.start(); B.start(); C.start(); }}
有A,B,C三个线程, A线程输出A, B线程输出B, C线程输出C
要求, 同时启动三个线程, 按顺序输出ABC, 循环10次
这是一个多线程协同的问题, 本身多线程是没有执行顺序的, 顺序不一定, Java在concurrent里面提供了多线程同步的支持
使用ReentrantLock来解决, 还有个state整数用来判断轮到谁执行了
1 import java.util.concurrent.locks.Lock; 2 import java.util.concurrent.locks.ReentrantLock; 3 4 public class ABC { 5 private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥 6 private static int state = 0; 7 8 static class ThreadA extends Thread { 9 @Override10 public void run() {11 for (int i = 0; i < 10;) {12 lock.lock();13 if (state % 3 == 0) {14 System.out.print("A");15 state++;16 i++;17 }18 lock.unlock();19 }20 }21 }22 23 static class ThreadB extends Thread {24 @Override25 public void run() {26 for (int i = 0; i < 10;) {27 lock.lock();28 if (state % 3 == 1) {29 System.out.print("B");30 state++;31 i++;32 }33 lock.unlock();34 }35 }36 }37 38 static class ThreadC extends Thread {39 @Override40 public void run() {41 for (int i = 0; i < 10;) {42 lock.lock();43 if (state % 3 == 2) {44 System.out.print("C");45 state++;46 i++;47 }48 lock.unlock();49 }50 }51 }52 53 public static void main(String[] args) {54 new ThreadA().start();55 new ThreadB().start();56 new ThreadC().start();57 }58 59 }
使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 思路简单
还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似
signal() 代替了 notify(),await() 代替了 wait(),signalAll() 代替 notifyAll()。await() 是等待的意思,调它 就是 阻塞写线程。signal 是发出信号的意思,调它 就是 唤醒读线程。
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import javax.xml.stream.events.StartDocument;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 {@Overridepublic void run() {lock.lock();try {for (int i = 0; i < 10; i++) {while (count % 3 != 0)A.await(); //如果不满足while条件,将本线程挂起System.out.print("A");count++;B.signal(); // A线程执行后,唤醒下一个线程B}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}static class ThreadB extends Thread {@Overridepublic void run() {lock.lock();try {for (int i = 0; i < 10; i++) {while (count % 3 != 1)B.await();//如果不满足while条件, 将本线程挂起System.out.print("B");count++;C.signal();// B线程执行后,唤醒下一个线程C}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}static class ThreadC extends Thread {@Overridepublic void run() {lock.lock();try {for (int i = 0; i < 10; i++) {while (count % 3 != 2)C.await();//如果不满足while条件, 将本线程挂起System.out.println("C");count++;A.signal();// C线程执行后,唤醒下一个线程A}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}public static void main(String[] args) throws InterruptedException {ThreadA threadA =new ThreadA();ThreadB threadB=new ThreadB();ThreadC threadC = new ThreadC();threadA.start();threadB.start();threadC.start();threadC.join();//让C线程执行完后在输出cout值否则可能cout在ABC线程都未完成时就输出结果。System.out.println(count);}}
使用信号量也可以, 这个思路最简单, 整个代码也比较简洁
1 import java.util.concurrent.Semaphore; 2 3 public class ABC3 { 4 private static Semaphore A = new Semaphore(1); 5 private static Semaphore B = new Semaphore(1); 6 private static Semaphore C = new Semaphore(1); 7 8 static class ThreadA extends Thread { 9 10 @Override11 public void run() {12 try {13 for (int i = 0; i < 10; i++) {14 A.acquire();15 System.out.print("A");16 B.release();17 }18 } catch (InterruptedException e) {19 e.printStackTrace();20 }21 }22 23 }24 25 static class ThreadB extends Thread {26 27 @Override28 public void run() {29 try {30 for (int i = 0; i < 10; i++) {31 B.acquire();32 System.out.print("B");33 C.release();34 }35 } catch (InterruptedException e) {36 e.printStackTrace();37 }38 }39 40 }41 42 static class ThreadC extends Thread {43 44 @Override45 public void run() {46 try {47 for (int i = 0; i < 10; i++) {48 C.acquire();49 System.out.println("C");50 A.release();51 }52 } catch (InterruptedException e) {53 e.printStackTrace();54 }55 }56 57 }58 59 public static void main(String[] args) throws InterruptedException {60 B.acquire(); C.acquire(); // 开始只有A可以获取, BC都不可以获取, 保证了A最先执行61 new ThreadA().start();62 new ThreadB().start();63 new ThreadC().start();64 }65 }
注意:
lock是需要lock所有者去释放的, 即谁lock, 谁释放, 不可以跨线程, 会报java.lang.IllegalMonitorStateException;
semaphore是没有所有者的说法, 可以跨线程释放和获取.
这是一道java笔试题, 多线程的问题现在越来越多的出现在笔试中, 要好好学习.
水平有限, 如有错漏, 请指针, 欢迎拍砖, 共同探讨!
参考文献:
- 深入浅出Java Concurrency:http://www.blogjava.net/xylz/archive/2010/07/08/325587.html
Lock的await/singal 和 Object的wait/notify 的区别
在使用Lock之前,我们都使用Object 的wait和notify实现同步的。举例来说,一个producer和consumer,consumer发现没有东西了,等待,produer生成东西了,唤醒。
线程consumer线程producersynchronize(obj){obj.wait();//没东西了,等待
}synchronize(obj){
obj.notify();//有东西了,唤醒
}
有了lock后,世道变了,现在是:
lock.lock();condition.await();
lock.unlock();lock.lock();
condition.signal();
lock.unlock();
为了突出区别,省略了若干细节。区别有三点:
- 1. lock不再用synchronize把同步代码包装起来;
- 2. 阻塞需要另外一个对象condition;
- 3. 同步和唤醒的对象是condition而不是lock,对应的方法是await和signal,而不是wait和notify。
为什么需要使用condition呢?简单一句话,lock更灵活。以前的方式只能有一个等待队列,在实际应用时可能需要多个,比如读和写。为了这个灵活性,lock将同步互斥控制和等待队列分离开来,互斥保证在某个时刻只有一个线程访问临界区(lock自己完成),等待队列负责保存被阻塞的线程(condition完成)。
通过查看ReentrantLock的源代码发现,condition其实是等待队列的一个管理者,condition确保阻塞的对象按顺序被唤醒。
在Lock的实现中,LockSupport被用来实现线程状态的改变,后续将更进一步研究LockSupport的实现机制。
- Java多线程:用三个线程控制循环输出10次ABC
- Java多线程:用三个线程控制循环输出10次ABC
- Java多线程:用三个线程控制循环输出10次ABC
- Java多线程:用三个线程控制循环输出10次ABC
- 用三个线程控制循环输出10次ABC
- Java多线程--三个线程分别打印a,b,c.请用多线程实现循环打印15次abc
- 多线程之三个ABC线程实现循环打印100次
- Java多线程 循环打印ABC 10次
- 循环打印三个线程,ABC 十次
- 循环输出10次ABC
- 多线程(至少三个线程)分别打印A、B、C,要求按ABC的顺序循环打印10次。
- java 多线程循环输出ABC
- java多线程:循环输出ABC
- 写一个程序三个线程分别输出A,B,C, 顺序输出ABC十次,用java实现
- 面试题--三个线程循环打印ABC 10次:另类解决方法
- 题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕打印10次ABC
- 启动三个线程A,B,C,打印10次 按照ABC的顺序输出
- 通过线程按照顺序循环输出ABC n次
- Welcome to JAVA!(第二课课后练习)
- 架构师速成-架构目标之正确性
- LeetCode Max Points on a Line
- 南阳理工ACM915 +-字符串
- Centos7 开放端口
- Java多线程:用三个线程控制循环输出10次ABC
- TestLink实验基础篇
- javascript中array类型的重排序方法
- 菜鸟,大牛和教主,三者的区别
- CMake交叉编译
- Spring中取得session,request等對象
- iOS开发-Day33-xml解析
- fragment重叠问题(add hide show方式)
- GSview 5.0可用注册码:55555-24868