这里将线程间通信的途径分为两类:同享内存和消息传递。
- volatile关键字的使用
就是利用volatile关键字的可见性,多个线程对它进行监控在其变量发生变化后执行对应线程的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| class ThreadCommunication { public static int STATE_RUN_A = 0; public static int STATE_RUN_B = 1; public static int STATE_RUN_C = 2;
volatile static int state = STATE_RUN_A; static int counter = 1;
public static void main(String[] args) {
Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } int c = 1 << 3; if (state == STATE_RUN_A) { System.out.println("threadA is running!"); for (int i = 0; i < c; i++) { if (i == 5) { state = STATE_RUN_B; break; } } } } });
Thread threadB = new Thread(new Runnable() { @Override public void run() { while (true) { if (state == STATE_RUN_B) { System.out.println("threadB is running!"); do { counter = counter << 1; } while (counter < 1 << 4);
state = STATE_RUN_C; break; } } } });
Thread threadC = new Thread(new Runnable() { @Override public void run() { while (true) { if (state == STATE_RUN_C) { System.out.println("threadC is running!"); do { counter = counter >> 1; } while (counter > 1);
System.out.println("threadC finish counter:" + counter); break; } } } });
threadA.start(); threadB.start(); threadC.start(); } }
|
- Object.wait()\notify()
在线程中调用该线程锁对象是wait方法是,该线程就被放入等待队列,直到被其他线程通知notify。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class ThreadCommunication { static int counter = 1; static Object lock = new Object();
public static void main(String[] args) {
Thread threadB = new Thread(new Runnable() { @Override public void run() { while (true) { synchronized (lock) { System.out.println("threadB is running!");
do { counter = counter << 1; } while (counter < 1 << 4); lock.notify(); break; } } } });
Thread threadC = new Thread(new Runnable() { @Override public void run() { while (true) { synchronized (lock) { if (counter == 1 << 4) { System.out.println("threadC is running!"); do { counter = counter >> 1; } while (counter > 1);
System.out.println("threadC finish counter:" + counter); break; } else { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } });
threadC.start(); threadB.start(); } }
|
- .join() {Thread.join}
当一个线程调用另外一个线程的join方法时,当前的线程就会阻塞等待被调用join方法的线程执行完毕后才能继续执行,所以join方法用来保证线程执行的顺序。
- CountDownLatch类
CountDownLatch类可以使线程等待其他线程执行完毕后再执行。
通过一个计数器来实现,CountDownLatch初始化传入的count代表等待count个线程执行完毕后等待的线程才能恢复执行。一般有几个应用场景:
场景一:
有多个线程依赖其他多个线程的执行完的结果,这是等待的await,被等待的线程执行完调用coutdown然后计数器减一,直到减为0就恢复多个线程的执行;
场景二:
实现多个线程同时执行,多个线程都设置await coutdown设置为1 在主线程中调用countdown让多个线程同时执行运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| class ThreadCommunication { static int counter = 1; static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) {
Thread threadA = new Thread(new Runnable() { @Override public void run() { try { System.out.println("threadA await"); countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("threadA is running!");
} });
Thread threadB = new Thread(new Runnable() { @Override public void run() { countDownLatch.countDown(); System.out.println("threadB is running!"); } });
Thread threadC = new Thread(new Runnable() { @Override public void run() { while (true) { do { counter = counter << 1; System.out.println("threadC is running! counter=" + counter);
} while (counter < 1 << 5);
countDownLatch.countDown(); break; } } });
threadA.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } threadB.start(); threadC.start(); } }
|
- LockSupport类
LockSupport是JDK中用来实现线程阻塞和唤醒的工具。使用它可以在任何场合使线程阻塞,可以指定任何线程进行唤醒。
LockSupport的设计核心是“许可”,park是等待一个许可,unpark是为某一线程提供一种许可,如果某线程A调用park,那么除非另外一个线程调用unpark(A)给A一个许可,否则线程A将阻塞在park操作上。还有就是unpark可以在park前调用,也就是先提供许可,等到后面调用park时在消耗之前的许可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class ThreadCommunication {
public static void main(String[] args) {
Thread threadA = new Thread(new Runnable() { @Override public void run() { System.out.println("threadA park"); LockSupport.park(); System.out.println("threadA is running!");
} });
Thread threadB = new Thread(new Runnable() { @Override public void run() { System.out.println("threadB park"); LockSupport.park(); System.out.println("threadB is running!");
System.out.println("threadB unpark threadA"); LockSupport.unpark(threadA); } });
threadA.start(); threadB.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main thread unpark threadB"); LockSupport.unpark(threadB); } }
|
全文完。