因为之前工作中一般单线程就能解决问题,很少用到多线程,即使用到也是在一些框架源码中别人封装好的,所以一直没有太在意这个问题。
但是前两天遇到一个题目刚好是考查关于多线程之间的同步,因此也就借这个机会看了下这方面的相关知识。
相关基础知识:
在多线程中经常使用到sleep()、wait()、notify()、notifyAll()方法,有几点需要注意:
1、sleep()是属于Thread类中的,而wait()、notify()、notifyAll()则是属于Object类中的;
2、sleep()调用后程序会暂停执行指定的时间,让出cpu资源给其他线程,但是他的监控状态依然保持着,不会释放锁,当指定的时间到了又会自动恢复运行状态。而wait()不仅会让出cpu资源,还会释放锁;
3、wait() 与 notify()、notifyAll ()在执行时,必须要先获得锁,因此一般与synchronized关键字一起使用;
4、当执行notify()、notifyAll()时,会唤醒一个处于等待该 锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。[notify()、notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。故,在实际编程中,我们应该尽量在线程调用notify()、notifyAll()后,立即退出临界区。即不要在notify()、notifyAll()后面再写一些耗时的代码]
上面都是一些关于线程的基础知识点,有了这些知识的铺垫,现在我们来看看题目的具体要求:
现有3个线程A、B、C,他们分别打印“早上”、“中午”、“晚上”,如何设计这三个线程之间的同步,让他们连续打印10次“早上中午晚上”的字样。
下面是小编自己敲键盘写的几行拙略的代码来实现这个功能:
package com.monkey.testthreadasync;
public class TestThreadAsync {
private static Thread threadA;
private static Thread threadB;
private static Thread threadC;
private static int count = 0;
private static int PRINT_COUNT = 10;
private static boolean flagA = true;
public static void main(String[] args) {
testThreadAsync();
}
//notify和wait方法都是object的方法,在调用这两个方法的时候应该获得锁(否则会出现 java.lang.IllegalMonitorStateException)
//即一般与synchronized关键字一起使用
private static void testThreadAsync() {
Object objA = new Object();
Object objB = new Object();
Object objC = new Object();
threadA = new Thread(){
public void run() {
while(flagA){
if(count>=PRINT_COUNT){
flagA = false;
continue;
}
synchronized (objA) {
System.out.println("早上");
count++;
try {
if (threadB != null && threadB.isAlive()){
synchronized (objB) {
objB.notify();
}
}else{
threadB.start();
}
objA.wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
threadB = new Thread(){
public void run() {
while(true){
synchronized (objB) {
System.out.println("中午");
if (threadC != null && threadC.isAlive()){
synchronized (objC) {
objC.notify();
}
}else{
threadC.start();
}
try {
objB.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
threadC = new Thread(){
public void run() {
while(true){
synchronized (objC) {
System.out.println("晚上");
synchronized (objA) {
objA.notify();
}
try {
//这里虽然前面执行了threadA.notify(),但是notify方法并不是立即释放锁,
//需要等待其后面的代码执行完了之后才会释放锁,因此notify后面的方法不应该执行耗时的操作
objC.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
threadA.start();
}
}
打印结果如下,基本实现了题目要求的功能:
如有需要改正或者优化的地方,欢迎留言讨论^^ ^^