要实现多个线程执行完成先后,就要知道如何实现线程之间的等待,java线程等待实现是join。java的jdk中join方法实现如下:
1 public final synchronized void join(long millis) 2 throws InterruptedException { 3 long base = System.currentTimeMillis(); 4 long now = 0; 5 6 if (millis < 0) { 7 throw new IllegalArgumentException("timeout value is negative"); 8 } 9 10 if (millis == 0) {11 while (isAlive()) {12 wait(0);13 }14 } else {15 while (isAlive()) {16 long delay = millis - now;17 if (delay <= 0) {18 break;19 }20 wait(delay);21 now = System.currentTimeMillis() - base;22 }23 }24 }
实现需求的方案一:
1 public class TestMain { 2 public static void main(String[] args) throws InterruptedException { 3 Thread T1 = new MyThread("T1"); 4 Thread T2 = new MyThread("T2"); 5 Thread T3 = new MyThread("T3"); 6 7 System.out.println("T1 start."); 8 T1.start(); 9 T1.join();10 System.out.println("T1 complete.");11 12 System.out.println("T2 start.");13 T2.start();14 T2.join();15 System.out.println("T2 complete.");16 17 System.out.println("T3 start.");18 T3.start();19 T3.join();20 System.out.println("T3 complete.");21 }22 }23 24 class MyThread extends Thread {25 public MyThread(String name) {26 setName(name);27 }28 29 @Override30 public void run() {31 for (int i = 0; i < 5; i++) {32 System.out.println(Thread.currentThread().getName() + ": " + i);33 try {34 // do something...35 Thread.sleep(100);36 } catch (InterruptedException e) {37 e.printStackTrace();38 }39 }40 }41 }
实现需求的方案二:
public class Test2Main { public static void main(String[] args) { final Thread T1 = new Thread(new Runnable() { @Override public void run() { System.out.println("T1..."); } }); final Thread T2 = new Thread(new Runnable() { @Override public void run() { try { T1.join(); }catch (InterruptedException ex){ ex.printStackTrace(); } System.out.println("T2..."); } }); final Thread T3 = new Thread(new Runnable() { @Override public void run() { try { T2.join(); }catch (InterruptedException ex){ ex.printStackTrace(); } System.out.println("T3..."); } }); T3.start(); T2.start(); T1.start(); }}
实现方案三:使用ReentrantLock来解决, 还有个state整数用来判断轮到谁执行了
import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ABC { private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥 private static int state = 0; static class ThreadA extends Thread { @Override public void run() { for (int i = 0; i < 10;) { lock.lock(); if (state % 3 == 0) { System.out.print("A"); state++; i++; } lock.unlock(); } } } static class ThreadB extends Thread { @Override public void run() { for (int i = 0; i < 10;) { lock.lock(); if (state % 3 == 1) { System.out.print("B"); state++; i++; } lock.unlock(); } } } static class ThreadC extends Thread { @Override public void run() { for (int i = 0; i < 10;) { lock.lock(); if (state % 3 == 2) { System.out.print("C"); state++; i++; } lock.unlock(); } } } public static void main(String[] args) { new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); } }
使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 思路简单
实现方案四:还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ABC2 { private static Lock lock = new ReentrantLock(); private static int count = 0; private static Condition A = lock.newCondition(); private static Condition B = lock.newCondition(); private static Condition C = lock.newCondition(); static class ThreadA extends Thread { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { while (count % 3 != 0) A.await(); // 会释放lock锁 System.out.print("A"); count++; B.signal(); // 唤醒相应线程 } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } static class ThreadB extends Thread { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { while (count % 3 != 1) B.await(); System.out.print("B"); count++; C.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } static class ThreadC extends Thread { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { while (count % 3 != 2) C.await(); System.out.println("C"); count++; A.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public static void main(String[] args) throws InterruptedException { new ThreadA().start(); new ThreadB().start(); ThreadC threadC = new ThreadC(); threadC.start(); threadC.join(); System.out.println(count); }}
实现方案五:使用信号量也可以, 这个思路最简单, 整个代码也比较简洁
import java.util.concurrent.Semaphore;public class ABC3 { private static Semaphore A = new Semaphore(1); private static Semaphore B = new Semaphore(1); private static Semaphore C = new Semaphore(1); static class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { A.acquire(); System.out.print("A"); B.release(); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadB extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { B.acquire(); System.out.print("B"); C.release(); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadC extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { C.acquire(); System.out.println("C"); A.release(); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { B.acquire(); C.acquire(); // 开始只有A可以获取, BC都不可以获取, 保证了A最先执行 new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); }}
注意:
lock是需要lock所有者去释放的, 即谁lock, 谁释放, 不可以跨线程, 会报java.lang.IllegalMonitorStateException;
semaphore是没有所有者的说法, 可以跨线程释放和获取.
方案三、四、五转自《》