線程通訊經常使用的方式有:html
兩個線程交替打印奇偶數,經過wait/notify
實現java
public class WaitNotify {
// 狀態鎖
private static Object lock = new Object();
private static Integer i = 0;
public void odd() {
while (i < 10) {
synchronized (lock) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void even() {
while (i < 10) {
synchronized (lock) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
WaitNotify waitNotify = new WaitNotify();
Thread t1 = new Thread(() -> waitNotify.odd(), "線程1");
Thread t2 = new Thread(() -> waitNotify.even(), "線程2");
t1.start();
t2.start();
}
}
結果:併發
線程2 - 0 線程1 - 1 線程2 - 2 線程1 - 3 線程2 - 4 線程1 - 5 線程2 - 6 線程1 - 7 線程2 - 8 線程1 - 9 線程2 - 10
volatile
修飾內存可見性ide
public class Volatile implements Runnable {
private static volatile Boolean flag = true;
@Override
public void run() {
while (flag) {
System.out.println(Thread.currentThread().getName() + " - 執行");
}
System.out.println("線程結束");
}
public static void main(String[] args) {
Thread t = new Thread(new Volatile());
t.start();
try {
Thread.sleep(5);
flag = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
結果:工具
Thread-0 - 執行 Thread-0 - 執行 Thread-0 - 執行 Thread-0 - 執行 Thread-0 - 執行 線程結束
CountDownLatch
能夠代替wait/notify
的使用,並去掉synchronized
,下面重寫第一個例子:spa
import java.util.concurrent.CountDownLatch;
public class CountDown {
private static Integer i = 0;
final static CountDownLatch countDown = new CountDownLatch(1);
public void odd() {
while (i < 10) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
countDown.countDown();
} else {
try {
countDown.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void even() {
while (i < 10) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
countDown.countDown();
} else {
try {
countDown.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
CountDown countDown = new CountDown();
Thread t1 = new Thread(() -> countDown.odd(), "線程1");
Thread t2 = new Thread(() -> countDown.even(), "線程2");
t1.start();
t2.start();
}
}
等待N個線程都達到某個狀態後繼續運行線程
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ": 準備...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("所有啓動完畢!");
}, "線程1").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ": 準備...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("所有啓動完畢!");
}, "線程2").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ": 準備...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("所有啓動完畢!");
}, "線程3").start();
}
}
結果:code
線程3: 準備... 線程2: 準備... 線程1: 準備... 所有啓動完畢! 所有啓動完畢! 所有啓動完畢!