最近在学习多线程时见到了一道题目,需要我们用两个线程,一个输出字母,一个输出数字,要求输出结果为1A2B3C4D...26Z
在学习一些视频和资料后,总结了几种比较简洁便于理解的方法:
1.使用LockSupport类中的park和unpark方法,park为阻塞当前线程,unpark(Thread thread)为唤醒传入参数所对应线程。该类属于java.util.concurrent.locks包。下面是代码:
static Thread t1 = null, t2 = null;
public static void main(String[] args) {
String[] aInt = {"1","2","3","4","5","6","7","8","9","10"};
char[] aChar = {'A','B','C','D','E','F','G','H','I','J'};
t1 = new Thread(()->{
for(String c:aInt){
System.out.print(c);
LockSupport.unpark(t2);//唤醒进程t2
LockSupport.park();//阻塞自身进程
}
},"t1");
t2 = new Thread(()->{
for(char c:aChar){
LockSupport.park();
System.out.print(c);
LockSupport.unpark(t1);
}
},"t2");
t1.start();
t2.start();
}
2.while自旋锁
enum ReadyToRun {T1,T2};
static volatile ReadyToRun r = ReadyToRun.T1;
public static void main(String[] args) {
String[] aInt = {"1","2","3","4","5","6","7","8","9","10"};
char[] aChar = {'A','B','C','D','E','F','G','H','I','J'};
new Thread(()->{
for(String c:aInt){
while (r!=ReadyToRun.T1){};//若r不为T1,自旋空转
System.out.print(c);
r = ReadyToRun.T2;
}
},"t1").start();
new Thread(()->{
for(char c:aChar){
while (r!=ReadyToRun.T2){};//若r不为T2,自旋空转
System.out.print(c);
r = ReadyToRun.T1;
}
},"t2").start();
}
3.经典方法 Synchronized加wait,notify操作
这里需要注意的问题是for循环结束之后必须再写一个o.notify(),如果没有调用这个方法,虽然最后的输出结果可能仍然正确,但最后总有一个线程阻塞在wait()操作而无法结束。即出现下面这种情况,输出完成但程序无法结束。
public static void main(String[] args) {
final Object o = new Object();
String[] aInt = {"1","2","3","4","5","6","7","8","9","10"};
char[] aChar = {'A','B','C','D','E','F','G','H','I','J'};
new Thread(()->{
synchronized (o){
for(String c:aInt){
System.out.print(c);
try {
o.notify();//叫醒t2
o.wait();//阻塞自己
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
},"t1").start();
new Thread(()->{
synchronized (o){
for(char c:aChar){
System.out.print(c);
try {
o.notify();//叫醒t1
o.wait();//阻塞自己
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
},"t2").start();
}