线程间的通信
- 常用的 wait()、notify()、notifyAll();在一个线程里面,唤醒其他拥有同样的锁的线程
/** * 使用wait(),notify(),notifyAll()时,代码块必须上锁 * @author : fzz */ public class Communicate { private static Object lock = new Object(); private static String str = null; public static void main(String[] args) { new Thread(()->{ synchronized(lock) { System.out.println(Thread.currentThread().getName() + "准备就绪!"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ": " + str); } }).start(); new Thread(()->{ synchronized(lock) { System.out.println(Thread.currentThread().getName() + "准备写入!"); str = "fzz"; System.out.println(Thread.currentThread().getName() + "写入完成: str = " + str); try { lock.notify(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } }
- Piped管道,通过管道字节流,实现线程间的数据交换
/** * @author : fzz */ public class PipedReader implements Runnable{ private PipedInputStream pipedInputStream; public PipedReader(PipedInputStream pipedInputStream) { this.pipedInputStream = pipedInputStream; } @Override public void run() { if (pipedInputStream!=null) { // 读取数据,以\n 结束 String collect = new BufferedReader(new InputStreamReader(pipedInputStream)).lines().collect(Collectors.joining("\n")); System.out.println("Reader:"+collect); try { pipedInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * @author : fzz */ public class PipedDemo { public static void main(String[] args) throws Exception { PipedInputStream pipedInputStream = new PipedInputStream(); PipedOutputStream pipedOutputStream = new PipedOutputStream(); //创建管道 pipedOutputStream.connect(pipedInputStream); new Thread(new PipedReader(pipedInputStream)).start(); BufferedReader br; try{ //读取数据 br = new BufferedReader(new InputStreamReader(System.in)); pipedOutputStream.write(br.readLine().getBytes()); }finally { pipedOutputStream.close(); } } }
- Thread.join()方法;在A线程内调用启动B线程,等待B线程执行完成,A线程再继续运行
/** * @author : fzz */ public class CommunicateDemo { public static void main(String[] args) { Thread thread = new Thread(() -> { System.out.println("我是线程1,我被调用了!"); }, "线程1"); new Thread(() -> { System.out.println(Thread.currentThread().getName()+"准备调用 线程1"); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"调用线程1 完成!"); }, "线程2").start(); } }
-
通过ThreadLocal实现,当前线程拥有自己的实例,互不干扰;ThreadLocal 底层用一个Map结构
key:当前线程 value:当前线程存放的值
/** * @author : fzz */ public class ThreadLocalDemo { private ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->0); public void inCreate(){ Integer num = threadLocal.get(); num++; System.out.println(Thread.currentThread().getName()+"====》"+ num); threadLocal.set(num); } public static void main(String[] args) { ThreadLocalDemo threadLocalDemo = new ThreadLocalDemo(); for (int i = 0; i < 3; i++) { //每个线程自己本地都有一份threadLocal,线程之间不会影响 new Thread(()->{ while(true){ threadLocalDemo.inCreate(); try { Thread.sleep(3000L); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } } 打印结果: Thread-0====》1 Thread-1====》1 Thread-2====》1 Thread-0====》2 Thread-2====》2 Thread-1====》2 Thread-1====》3 Thread-0====》3 Thread-2====》3 Thread-2====》4 Thread-1====》4 Thread-0====》4
- ,Condition实现(相比 wait,notify() 可以有多的等待,唤醒,通过newCondition,指定性强)
/** * @author : fzz */ public class ConfitionDemo { static Lock lock = new ReentrantLock(); static String str = null; static Condition condition = lock.newCondition(); public static void main(String[] args) { new Thread(()->{ lock.lock(); System.out.println(Thread.currentThread().getName() + "准备就绪!"); try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ": " + str); lock.unlock(); }).start(); new Thread(()->{ lock.lock(); System.out.println(Thread.currentThread().getName() + "准备写入!"); str = "fzz"; System.out.println(Thread.currentThread().getName() + "写入完成: str = " + str); try { condition.signal(); } catch (Exception e) { e.printStackTrace(); } lock.unlock(); }).start(); } }
- CountDownLatch:通过countDown计数减一,调用 await() 等待所有线程执行完成再继续
/** * @author : fzz */ public class CountDownLatchDemo { public static void main(String[] args) throws Exception{ //如果没有用countDownLatch 运行结束可能在中间打印 CountDownLatch countDownLatch = new CountDownLatch(10); for (int i = 0; i < 10; i++) { int finalI = i; new Thread(()->{ System.out.println(Thread.currentThread().getName()+":"+ finalI); countDownLatch.countDown(); }).start(); } countDownLatch.await(); System.out.println("运行结束!"); } } // 用CountDownLatch: 没用CountDownLatch: // Thread-0:0 Thread-0:0 // Thread-7:7 Thread-7:7 // Thread-8:8 Thread-8:8 // Thread-6:6 Thread-6:6 // Thread-5:5 运行结束! // Thread-4:4 Thread-4:4 // Thread-3:3 Thread-3:3 // Thread-1:1 Thread-1:1 // Thread-2:2 Thread-2:2 // Thread-9:9 Thread-9:9 // 运行结束! Thread-5:5
- CyclicBarrier:多个线程等到同一状态,一起运行
public class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(5); for (int i = 0; i < 5; i++) { int finalI = i; new Thread(()->{ try { Thread.sleep(finalI *1000L); System.out.println(Thread.currentThread().getName()+"准备就绪!"); cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"开始!"); }).start(); } } } // Thread-0准备就绪! // Thread-1准备就绪! // Thread-2准备就绪! // Thread-3准备就绪! // Thread-4准备就绪! // Thread-4开始! // Thread-0开始! // Thread-1开始! // Thread-2开始! // Thread-3开始!
- semaphore信号量:起到一个限流的作用,只允许几个线程运行
public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for (int i = 0; i < 5; i++) { new Thread(()->{ try{ //占用 semaphore.acquire(); System.out.println(Thread.currentThread().getName()); Thread.sleep(3000L); }catch (Exception e){ e.printStackTrace(); } finally{ //释放 semaphore.release(); } }).start(); } } }
- Exchanger(成对使用):用于交换数据,当两个线程都达到exchanger时候,交换数据;否则一直等待
public class ExchangerDemo { public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<>(); String str1 = "hello"; String str2 = "world"; new Thread(()->{ System.out.println(Thread.currentThread().getName()+"初始化值===>"+str1); try { //交换后的返回值 String exchange = exchanger.exchange(str1); System.out.println(Thread.currentThread().getName()+"交换后值===>"+exchange); } catch (InterruptedException e) { e.printStackTrace(); } },"线程一").start(); new Thread(()->{ System.out.println(Thread.currentThread().getName()+"初始化值===>"+str2); try { //交换后的返回值 String exchange = exchanger.exchange(str2); System.out.println(Thread.currentThread().getName()+"交换后值===>"+exchange); } catch (InterruptedException e) { e.printStackTrace(); } },"线程二").start(); } } 线程一初始化值===>hello 线程二初始化值===>world 线程二交换后值===>hello 线程一交换后值===>world