题目:要求写个Java程序,一个线程专门打印a,另一个线程专门打印b,要求输出为轮流显示a和b,并重复50遍。
- 用
CyclicBarrier
。CyclicBarrier允许一组线程互相等待,直到全部到达某个公共屏障点后,屏障才会打开,所有线程才会继续执行。
import java.util.concurrent.CyclicBarrier;
public class AB1 {
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(2);
new Thread(() -> {
for (int i = 0; i < 50; i++) {
System.out.println("a");
try {
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "ta").start();
new Thread(() -> {
for (int i = 0; i < 50; i++) {
while (cb.getNumberWaiting() < 1)
;
System.out.println("b");
try {
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "tb").start();
}
}
- 用CountDownLatch。CountDownLatch允许一个或多个线程等待其他线程完成操作后再执行。对于此题的情景应该不如CyclicBarrier适用,因为它不能循环使用。
import java.util.concurrent.CountDownLatch;
class AB2 {
public static void main(String[] args) {
CountDownLatch[] latch1 = {new CountDownLatch(1)};
CountDownLatch[] latch2 = {new CountDownLatch(1)};
new Thread(() -> {
for (int i = 0; i < 50; i++) {
System.out.println("a");
latch1[0].countDown();
try {
latch2[0].await();
latch2[0] = new CountDownLatch(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "ta").start();
new Thread(() -> {
for (int i = 0; i < 50; i++) {
try {
latch1[0].await();
latch1[0] = new CountDownLatch(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b");
latch2[0].countDown();
}
}, "tb").start();
}
}
- 信号量Semaphore, 个人推荐。也可以借鉴1中的用法。
import java.util.concurrent.Semaphore;
class AB3 {
public static void main(String[] args) {
Semaphore semaphoreB = new Semaphore(0);
Semaphore semaphoreA = new Semaphore(0);
new Thread(() -> {
for (int i = 0; i < 50; i++) {
System.out.println("a");
semaphoreB.release();
try {
semaphoreA.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "ta").start();
new Thread(() -> {
for (int i = 0; i < 50; i++) {
try {
semaphoreB.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b");
semaphoreA.release();
}
}, "tb").start();
}
}
- 直接使用AtomicInteger :
import java.util.concurrent.atomic.AtomicInteger;
class AB4 {
public static void main(String[] args) {
AtomicInteger lock = new AtomicInteger();
new Thread(() -> {
for (int i = 0; i < 50; i++) {
System.out.println("a");
lock.incrementAndGet();
while(lock.get() == 1)
;
}
}, "ta").start();
new Thread(() -> {
for (int i = 0; i < 50; i++) {
while(lock.get() < 1)
;
System.out.println("b");
lock.getAndDecrement();
}
}, "tb").start();
}
}
- 使用Thread.join()方法:
public class AB5 {
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
Thread threadA = new Thread(() -> {
System.out.println("a");
}, "ta");
threadA.start();
try {
threadA.join();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
Thread threadB = new Thread(() -> {
System.out.println("b");
}, "tb");
threadB.start();
try {
threadA.join();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
- 使用synchronized及锁对象的wait/notify方法,或者使用Lock及其Condition的await/signal方法。这两种其实是我最先尝试的,但是失败了,直到参考了1。失败的原因是,当一个线程调用锁对象的notify方法(或者Condition的signal方法),另一个线程调用锁对象的wait方法(或者Condition的await方法),如果前者先于后者调用,那它实际上起不到我们期望的唤醒作用。所以成功的做法是干脆把所有wait(或者await)方法前置了。
class AB6 {
public static void main(String[] args) {
int[] num = { 0 };
final Object lock = new Object();
new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 50; ++i) {
while (num[0] % 2 != 0) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("a");
num[0]++;
lock.notify();
}
}
}, "ta").start();
new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 50; ++i) {
while (num[0] % 2 != 1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("b");
num[0]++;
lock.notify();
}
}
}, "tb").start();
}
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class AB7 {
public static void main(String[] args) {
int[] num = { 0 };
final ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
try {
lock.lock();
for (int i = 0; i < 50; ++i) {
while (num[0] % 2 != 0) {
condition.await();
}
System.out.println("a");
num[0]++;
condition.signal();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "ta").start();
new Thread(() -> {
try {
lock.lock();
for (int i = 0; i < 50; ++i) {
while (num[0] % 2 != 1) {
condition.await();
}
System.out.println("b");
num[0]++;
condition.signal();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "tb").start();
}
}