最近面试遇到一个要求多线程顺序打印的题目,作为一个两年的java开发居然写错了,当时觉得丢脸极了,想死在当场,下面就总结一些集中写法。
题目:
// 开启多个线程,按照顺序打印数字,如
线程1打印1
线程2打印2
线程3打印3
线程4打印4
。。。
方法1:while循环
第一种最简单的,我们不用锁,通过循环的方式(CAS)算法来达到加锁的目的
public class Test {
public static int cur = 1;
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
test.print();
}
public void print() throws InterruptedException {
for (int i = 1; i < 1001; i++) {
final int finalI = i;
new Thread(new Runnable() {
@Override
public void run() {
while (cur != finalI);
System.out.println(cur);
Test.cur ++;
}
}).start();
}
}
}
这种巧妙的使用while循环达到加锁的目的,不需要进行同步操作。
方法2: ReentrantLock
这个方法我们使用ReentrantLock+Condition来实现多线程同步,每个线程在执行之前,需要先判断一下当前变量是否是自己要打印的那个,不是的话就等待,否则就打印变量,之后再通知下一个线程执行。
public void printNumber2() {
ReentrantLock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
Thread thread1 = new Thread(() -> {
lock.lock();
while (Test.cur != 1) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Test.cur);
Test.cur++;
condition2.signal();
lock.unlock();
});
Thread thread2 = new Thread(() -> {
lock.lock();
while (Test.cur != 2) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Test.cur);
Test.cur++;
condition3.signal();
lock.unlock();
});
Thread thread3 = new Thread(() -> {
lock.lock();
while (Test.cur != 3) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Test.cur);
Test.cur = 1;
condition1.signal();
lock.unlock();
});
thread1.start();
thread2.start();
thread3.start();
}
上面这种写法有点问题,如果面试官让我写100个线程,那我需要创建100个Condition吗?
方法3: synchronized
Object对象自带一个锁,可以使用synchronized和对象自带的锁来达到同步的操作。
public class PrintNumbers {
private static final Object lock = new Object();
private static int currentNumber = 1;
private static final int MAX_NUMBER = 101;
private static final int THREAD_COUNT = 100;
public static void main(String[] args) {
for (int i = 1; i <= THREAD_COUNT; i++) {
final int threadId = i;
new Thread(() -> {
synchronized (lock) {
while (currentNumber <= MAX_NUMBER) {
if (currentNumber == threadId) {
System.out.println(currentNumber);
currentNumber = (currentNumber + 1) % 101;
lock.notifyAll();
break;
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
}
}