个人记录: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)
语法不熟悉啊。哎。
果然啊,我还是最菜的。
我刷题,我骄傲。