两个线程同时开启,如果让两个线程顺序执行
- synchronized,然后用 wait notify
- locksupport 的 park,unpark
- cas,不停的去判断另一个线程运行完了没有
- 使用很多种 aqs 实现,如 countdownlatch,semaphore,reentrylock 等
- blockingqueue
- exchanger
- 单一线程池——控制线程顺序运行 8.future 9.pipedinputstram 和 pipedoutputstream
使用join()
join在线程里面意味着“插队”,哪个线程调用join代表哪个线程插队先执行——但是插谁的队是有讲究了,不是说你可以插到队头去做第一个吃螃蟹的人,而是插到在当前运行线程的前面,比如系统目前运行线程A,在线程A里面调用了线程B.join方法,则接下来线程B会抢先在线程A面前执行,等到线程B全部执行完后才继续执行线程A。
而在JDK的解释中,join方法被解释成等待这个线程死亡,也就是等待这个线程全部执行完后才继续执行接下来的进程。
@Test
@SneakyThrows
public void useJoin() {
Thread t1 = new Thread(() -> System.out.println(T1_WORD));
Thread t2 = new Thread(() -> {
try {
t1.join(); //插队
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(T2_WORD);
});
t1.start();
t2.start();
t2.join();
}
使用synchronized关键字和 wait¬ify
private static volatile Integer STATUS = 1;
@Test
@SneakyThrows
public void useSynchronized() {
Object object = new Object();
Thread t1 = new Thread(() -> {
while (true) {
while (STATUS == 1) {
synchronized (object) {
try {
System.out.println(T1_WORD);
STATUS = 2;
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}, "T1");
Thread t2 = new Thread(() -> {
while (true) {
while (STATUS == 2) {
synchronized (object) {
try {
System.out.println(T2_WORD);
TimeUnit.SECONDS.sleep(2);
STATUS = 1;
object.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}, "T2");
t2.start();
t1.start();
t2.join();
}
使用LockSupport (链接)
@Test
@SneakyThrows
public void useLockSupport() {
Thread t2 = new Thread(() -> {
LockSupport.park();
System.out.println(T2_WORD);
});
Thread t1 = new Thread(() -> {
System.out.println(T1_WORD);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
LockSupport.unpark(t2);
});
t1.start();
t2.start();
t2.join();
}
使用CAS
private final AtomicBoolean THREAD_A = new AtomicBoolean(false);
@Test
@SneakyThrows
public void useCas() {
Thread t1 = new Thread(() -> {
System.out.println(T1_WORD);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
THREAD_A.set(true);
});
Thread t2 = new Thread(() -> {
while (true) {
if (THREAD_A.get()) {
System.out.println(T2_WORD);
break;
}
}
});
t1.start();
t2.start();
t2.join();
}
使用很多种 aqs 实现,如 countdownlatch,semaphore,reentrylock 等
CountDownLatch(2021.04.02 修正)
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(1);
@Test
@SneakyThrows
public void useCountDownLatch() {
Thread t1 = new Thread(() -> {
try {
while (true) {
while (STATUS == 1) {
System.out.println(T1_WORD);
COUNT_DOWN_LATCH.countDown();
STATUS = 2;
COUNT_DOWN_LATCH.await();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
while (true) {
while (STATUS == 2) {
COUNT_DOWN_LATCH.await();
System.out.println(T2_WORD);
TimeUnit.SECONDS.sleep(2);
STATUS = 1;
COUNT_DOWN_LATCH.countDown();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t2.join();
}
Semaphore(2021.04.02 修正)
private static final Semaphore SEMAPHORE_A = new Semaphore(1);
private static final Semaphore SEMAPHORE_B = new Semaphore(0);
@SneakyThrows
@Test
public void useSemaphore() {
Thread t1 = new Thread(() -> {
try {
while (true) {
SEMAPHORE_A.acquire();
System.out.println(T1_WORD);
SEMAPHORE_B.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
while (true) {
SEMAPHORE_B.acquire();
System.out.println(T2_WORD);
System.out.println("-------------------");
TimeUnit.SECONDS.sleep(2);
SEMAPHORE_A.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t2.join();
}
ReentryLock
private static final ReentrantLock REENTRANT_LOCK = new ReentrantLock();
@Test
@SneakyThrows
public void useReentryLock() {
Thread t1 = new Thread(() -> {
try {
REENTRANT_LOCK.lock();
System.out.println(T1_WORD);
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
REENTRANT_LOCK.unlock();
}
});
Thread t2 = new Thread(() -> {
try {
REENTRANT_LOCK.lock();
System.out.println(T2_WORD);
} finally {
REENTRANT_LOCK.unlock();
}
});
t1.start();
t2.start();
t2.join();
}
使用BlockingQueue:take(),put()
private static final BlockingQueue<Integer> BLOCKING_QUEUE = new ArrayBlockingQueue<>(1);
@Test
@SneakyThrows
public void useBlockingQueue() {
Thread t1 = new Thread(() -> {
try {
System.out.println(T1_WORD);
TimeUnit.SECONDS.sleep(3);
BLOCKING_QUEUE.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
Integer take = BLOCKING_QUEUE.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(T2_WORD);
});
t1.start();
t2.start();
t2.join();
}
使用Exchanger
private static final Exchanger<Boolean> EXCHANGER = new Exchanger<>();
@Test
@SneakyThrows
public void useExchanger() {
Thread t1 = new Thread(() -> {
System.out.println(T1_WORD);
try {
EXCHANGER.exchange(true);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
if (EXCHANGER.exchange(false)) {
System.out.println(T2_WORD);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t2.join();
}
使用单线程池
@Test
@SneakyThrows
public void useSingleThreadPool() {
ExecutorService executor = Executors.newSingleThreadExecutor();
Thread t1 = new Thread(() -> {
System.out.println(T1_WORD);
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
System.out.println(T2_WORD);
COUNT_DOWN_LATCH.countDown();
});
executor.execute(t1);
executor.execute(t2);
COUNT_DOWN_LATCH.await();
executor.shutdown();
}
使用Future
@Test
@SneakyThrows
public void useFuture() {
Future<Void> future = CompletableFuture.runAsync(() -> {
System.out.println(T1_WORD);
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
future.get();
System.out.println(T2_WORD);
}
使用PipedInputStream和PipedOutputStream
@Test
@SneakyThrows
public void usePipedInputStreamAndPipedOutputStream() {
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pis.connect(pos);
Thread t1 = new Thread(() -> {
System.out.println(T1_WORD);
try {
TimeUnit.SECONDS.sleep(3);
pos.write(T1_WORD.getBytes());
} catch (InterruptedException | IOException e) {
e.printStackTrace();
} finally {
try {
pos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() -> {
byte[] byteArray = new byte[20];
try {
int readLength = pis.read(byteArray);
while (readLength != -1) {
String newData = new String(byteArray, 0, readLength);
System.out.println("读出数据:" + newData);
readLength = pis.read(byteArray);
}
System.out.println(T2_WORD);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
pis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
t2.join();
}