有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。

个人记录:2018年,工作的第6到7个年头。
重点研究自己不太擅长的技术:分布式、高并发、大数据量、数据库优化、高性能、负载均衡等。
刷题是一种态度,是一种好习惯。

有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。

就是线程之间的协作。请问咋做呢?这种情况是只用一个锁来实现可以吗?
问题出处:http://ifeve.com/question/%e6%9c%893%e4%b8%aa%e7%ba%bf%e7%a8%8babc%e3%80%82%e6%8c%89%e7%85%a7abc%e6%9d%a5%e8%bf%90%e8%a1%8c%ef%bc%88a%e7%ba%bf%e7%a8%8b%e8%be%93%e5%87%baa%ef%bc%8cb%e7%ba%bf%e7%a8%8b%e8%be%93%e5%87%bab%ef%bc%8c/

个人实践
第1次:循环中,创建Thread,用join等待前一个进程结束。
写完之后,打算把Thread抽象出来。
同时,发现循环里新建Thread,就不止3个Thread了。


package cn.fansunion.threadabc;


//有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。
public class ThreadABCTest1 {


public static void main(String[] args) {
for(int index=0;index<3;index++){
Thread aThread = new Thread(new Runnable(){


@Override
public void run() {
System.out.println("A");

}

});
aThread.start();
try {
aThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread bThread = new Thread(new Runnable(){


@Override
public void run() {
System.out.println("B");

}

});
bThread.start();
try {
bThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread cThread = new Thread(new Runnable(){


@Override
public void run() {
System.out.println("C");

}

});
cThread.start();
try {
cThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}


}


}
多次输出结果:
A
B
C
A
B
C
A
B
C


第2次:
package cn.fansunion.threadabc;


//有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。
public class ThreadABCTest2 {

public static void main(String[] args) {
ThreadTask aThread = new ThreadTask("A");
ThreadTask bThread = new ThreadTask("B");
ThreadTask cThread = new ThreadTask("C");

for(int index=0;index<10;index++){
aThread.start();
try {
aThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
bThread.start();
try {
bThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
cThread.start();
try {
cThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}


}

}
package cn.fansunion.threadabc;


public class ThreadTask extends Thread {


private String word;


public ThreadTask(String word) {
this.word = word;
}


@Override
public void run() {
System.out.println(word);


}


}


多次输出结果:
A
B
C
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at cn.fansunion.threadabc.ThreadABCTest2.main(ThreadABCTest2.java:12)

报错原因:
join方法:Waits for this thread to die. 
调用join之后,线程就死亡了。


第3次:
3个线程,用抢占锁的方式,先后执行。


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


//有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。
public class ThreadABCTest3 {

private static Lock lock = new ReentrantLock();

public static void main(String[] args) {
ThreadTask aThread = new ThreadTask("A");
ThreadTask bThread = new ThreadTask("B");
ThreadTask cThread = new ThreadTask("C");

for(int index=0;index<10;index++){
lock.lock();
aThread.start();
lock.unlock();
lock.lock();
bThread.start();
lock.unlock();
lock.lock();
cThread.start();
lock.unlock();
}
}



}




多次输出结果:
A
B
C
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at cn.fansunion.threadabc.ThreadABCTest3.main(ThreadABCTest3.java:18)

报错原因:
start方法也只能调用1次,尴尬了。
另外,还有1个潜在问题。(尚未证实)
start方法调用之后,线程也不是立即开始执行。
虽然aTrhead先于bThread调用start,但是不代表aThread先执行。

第4次:只创建3个线程,线程内部for循环输出。
通过lock获得锁,unlock的时候,顺序无法保证。
再次失败。
package cn.fansunion.threadabc;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


//有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。
public class ThreadABCTest4 {


private static Lock lock = new ReentrantLock();


public static void main(String[] args) {
final int maxNum = 3;


Thread aThread = new Thread(new Runnable() {


@Override
public void run() {
for (int index = 0; index < maxNum; index++) {
lock.lock();
System.out.println("A");
lock.unlock();
}


}


});
Thread bThread = new Thread(new Runnable() {


@Override
public void run() {
for (int index = 0; index < maxNum; index++) {
lock.lock();
System.out.println("B");
lock.unlock();
}


}


});
Thread cThread = new Thread(new Runnable() {


@Override
public void run() {
for (int index = 0; index < maxNum; index++) {
lock.lock();
System.out.println("C");
lock.unlock();
}


}


});
aThread.start();


bThread.start();


cThread.start();
}


}


输出结果:顺序无法保证,每次结果不确定。
A
A
A
C
C
C
B
B
B




第5次:
网友提到了线程之间的协同,应该是正解。
平时,几乎没有需要写这种类型的线程协同代码。
线程本来就强调并发执行,现在非要强调先后顺序,还有必要搞多线程么。


package cn.fansunion.threadabc;


//有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。
public class ThreadABCTest5 {


public static void main(String[] args) {
final int maxNum = 3;


final Thread cThread = new Thread(new Runnable() {


@Override
public void run() {
for (int index = 0; index < maxNum; index++) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("C");
}


}


});

final Thread  bThread = new Thread(new Runnable() {


@Override
public void run() {
for (int index = 0; index < maxNum; index++) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B");
cThread.notify();
}


}


});

Thread aThread =new Thread(new Runnable() {


@Override
public void run() {
for (int index = 0; index < maxNum; index++) {
System.out.println("A");
bThread.notify();
}


}


});

cThread.start();
bThread.start();
aThread.start();



}


}




 运行结果:
 Exception in thread "Thread-0" Exception in thread "Thread-1" A
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at cn.fansunion.threadabc.ThreadABCTest5$1.run(ThreadABCTest5.java:20)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at cn.fansunion.threadabc.ThreadABCTest5$3.run(ThreadABCTest5.java:55)
at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at cn.fansunion.threadabc.ThreadABCTest5$2.run(ThreadABCTest5.java:37)
at java.lang.Thread.run(Thread.java:745)


语法不熟悉啊。哎。

果然啊,我还是最菜的。


我刷题,我骄傲。

猜你喜欢

转载自blog.csdn.net/FansUnion/article/details/79630734