JUC
java.util.concurrent
并发锁:

Lock接口
有三个实现类:ReentrantLock(可重入锁,常用),ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock
方法:lock()获得锁 unlock() 释放锁

公平锁:十分公平,可以先来后到
非公平锁:十分不公平:可以插队(默认)synchronized

使用lock 锁的三步曲:
1.先创建一个lock锁实例 Lock l = new ReentrantLock();
2.获得锁 l.lock();
3.释放锁 l.unlock();写在finally里面

消费者与生产者模式:(判断等待条件,业务,通知)
1.通过Synchonized关键字来实现生产者消费者模式(代码里面用到了if判断语句,当有多对生产者消费者线程的时候,这种容易产生虚假唤醒)所以要用到while
package JUC.ProducerAndConsumer; public class First { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(() -> {for (int i = 0; i < 10; i++)ticket.produce();}, "A").start(); new Thread(() -> {for (int i = 0; i < 10; i++)ticket.consume();}, "B").start(); } } //生产者消费者模式 // 判断等待 业务 唤醒 class Ticket { private int number = 0; // 如果数量为0 的时候则生产 // 数量为1的时候则唤醒另外一个线程执行 public synchronized void produce() { if (number != 0) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } number++; System.out.println(Thread.currentThread().getName() + "=>" + number); this.notifyAll(); } public synchronized void consume() { // 当数量为0的时候则等待 if (number == 0) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } number--; System.out.println(Thread.currentThread().getName() + "=>" + number); this.notifyAll(); } }
对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用: 
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
     }
2.使用JUC实现生产者消费者模式:(await(),signal())
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
Condition 实例实质上被绑定到一个锁定上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
步骤:
1.实例化一把锁 Lock lock = new ReentrantLock();
2.为特定 Lock 实例获得 Condition 实例 Condition condition = lock.newCondition();
3.上锁 lock.lock();
4.写业务代码(判断等待条件,等待,业务,释放锁)
5.释放锁 lock.unlock();
package JUC.ProducerAndConsumer; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.*; public class JUCProducerAndConsumer { public static void main(String[] args) { Ticket1 ticket = new Ticket1(); new Thread(()-> {for(int i = 0;i<10;i++) ticket.produce();},"A").start(); new Thread(()->{for(int i = 0;i<10;i++) ticket.consume();},"B").start(); new Thread(()-> {for(int i = 0;i<10;i++) ticket.produce();},"C").start(); new Thread(()-> {for(int i = 0;i<10;i++) ticket.consume();},"D").start(); } } class Ticket1{ private int number = 0; //先创建一个锁实例 Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //当数量不为0的时候要等待 public void produce() { lock.lock(); try { //业务代码 while(number!=0) { condition.await(); } number++; System.out.println(Thread.currentThread().getName()+"=>"+number); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); }finally { //释放锁 lock.unlock(); } } public void consume() { lock.lock(); try { while(number == 0) { condition.await(); } number--; System.out.println(Thread.currentThread().getName()+"=>"+number); condition.signalAll(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { lock.unlock(); } } }
3.使用Condition实现精准唤醒通知:
package JUC.ProducerAndConsumer; import java.util.concurrent.locks.*; import java.util.concurrent.locks.ReentrantLock; public class ConditionAccurateNotify { public static void main(String[] args) { Data data = new Data(); new Thread(()->{for(int i = 0;i<10;i++) data.printA();},String.valueOf(1)).start(); new Thread(()->{for(int i = 0;i<10;i++) data.printB();},String.valueOf(2)).start(); new Thread(()->{for(int i = 0;i<10;i++) data.printC();},String.valueOf(3)).start(); } } class Data{ private int number = 2; Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); public void printA() { lock.lock(); try { while(number!=1) { condition1.await(); } System.out.println(Thread.currentThread().getName()+"=>AAAAAAA"); number = 2; condition2.signal(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { lock.unlock(); } } public void printB() { lock.lock(); try { while(number!=2) { condition2.await(); } number = 3; System.out.println(Thread.currentThread().getName()+"=>BBBBB"); condition3.signal(); }catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { lock.unlock(); } } public void printC() { lock.lock(); try { while(number!=3) { condition3.await(); } number = 1; System.out.println(Thread.currentThread().getName()+"=>CCCCCCC"); condition1.signal(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { lock.unlock(); } } }
锁的八大问题:
1.只有一个资源对象 phone, synchonized,锁的对象是方法的调用者。两个方法用的是同一把锁,谁先拿到就先调用谁。
//会先输出 Send Message! 即使msg()方法里面调用了sleep()方法,但是sleep()方法是抱着锁睡觉的。如果调用wait()方法,那么就会先输出call....
package JUC.ProducerAndConsumer; import java.util.concurrent.TimeUnit; public class EightQuestions { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{phone.msg();}).start(); try { TimeUnit.SECONDS.sleep(1);//这里的sleep其实是main线程在这里睡眠 } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } new Thread(()->{phone.call();}).start(); } } class Phone{ public synchronized void msg() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } System.out.println("Send Message!"); } public synchronized void call() { System.out.println("Call..."); } }
2.如果增加一个普通方法:(先打印Hello, 在打印Send Message!)
分析:
首先,phone1对象拿到锁先执行了msg()方法,但执行msg()的时候睡眠了2秒,而main程序只会睡眠1s.main睡完以后就会接着执行调用sayHello()方法,然后msg()再醒来执行,所以是先打印Hello,再打印Send Message!
TimeUnit.SECONDS.sleep(1);
package JUC.ProducerAndConsumer; import java.util.concurrent.TimeUnit; public class EightQuestions { public static void main(String[] args) { Phone phone1 = new Phone(); new Thread(()->{phone1.msg();},"A").start(); try { System.out.println(Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } new Thread(()->{phone1.sayHello();},"B") .start(); // new Thread(()->{phone1.call();},"B").start(); } } class Phone{ public synchronized void msg() { try { TimeUnit.SECONDS.sleep(2); System.out.println("Send Message!"); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } public synchronized void call() { System.out.println("Call..."); } public void sayHello() { System.out.println("Say Hello..."); } }
3.创建两个资源对象(先打印Call!再打印Send msg!)
分析:此时有两个资源对象,phone1和phone2,那么synchonized锁的就是不同的对象
在调用sendMsg()的时候,phone1资源睡了3s,然后主线程睡眠了1S,那么主线程就会先醒来,然后接着就有phone2资源开始调用call()方法,所以先打印先打印Call!再打印Send msg!
package JUC.ProducerAndConsumer; import java.util.concurrent.TimeUnit; public class StaticMethod { public static void main(String[] args) { Mobile phone1 = new Mobile(); Mobile phone2 = new Mobile(); new Thread(()->{phone1.sendMsg();}).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } new Thread(()->{phone2.call();}).start(); } } class Mobile{ public synchronized void sendMsg() { try { TimeUnit.SECONDS.sleep(3); System.out.println("Send Msg!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public synchronized void call() { System.out.println("Call!"); } }
4.增加一个静态方法,那么锁的是类模板(而类模板永远只有一份)
先打印Send msg!再打印Call!
package JUC.ProducerAndConsumer; import java.util.concurrent.TimeUnit; public class StaticMethod { public static void main(String[] args) { Mobile phone1 = new Mobile(); Mobile phone2 = new Mobile(); new Thread(()->{phone1.sendMsg();}).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } new Thread(()->{phone2.call();}).start(); } } class Mobile{ public static synchronized void sendMsg() { try { TimeUnit.SECONDS.sleep(3); System.out.println("Send Msg!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static synchronized void call() { System.out.println("Call!"); } }
5.一个静态同步方法,一个普通同步的方法
(先打印Call!再打印Send Msg!)
分析:调用sendMsg()会锁类模板,而调用call()方法会锁对象,锁的对象不一样,所以不会干扰。
package JUC.ProducerAndConsumer; import java.util.concurrent.TimeUnit; public class StaticMethod { public static void main(String[] args) { Mobile phone1 = new Mobile(); new Thread(()->{phone1.sendMsg();}).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } new Thread(()->{phone1.call();}).start(); } } class Mobile{ public static synchronized void sendMsg() { try { TimeUnit.SECONDS.sleep(3); System.out.println("Send Msg!"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public synchronized void call() { System.out.println("Call!"); } }
集合类的不安全性
List集合的不安全性解决办法:
- 使用Vector
- 使用Collections类里面的静态方法Collections.synchronizedList
public class SaveArrayListTest { public static void main(String[] args) { List<String> list = Collections.synchronizedList(new ArrayList<>()); for(int i = 0;i<10;i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 5)); System.out.println(list); },String.valueOf(i)).start(); } } }
3.使用JUC里面的类(CopyOnWriteArrayList)

package JUC.List; import java.util.List; import java.util.UUID; import java.util.concurrent.*;
public class JUCArrayListTest { public static void main(String[] args) { List<String> list = new CopyOnWriteArrayList<String>(); for(int i=1;i<=10;i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 6)); System.out.println(Thread.currentThread().getName()+"==>"+list); },String.valueOf(i)).start(); } } }
Set不安全性:
1.使用Collections类里面的静态方法:synchonizedSet();
public static <T> Set<T> synchronizedSet(Set<T> s)
返回由指定 set 支持的同步(线程安全的)set。为了保证按顺序访问,必须通过返回的 set 完成对底层 set 的所有访问。
package JUC.Set; import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.*; public class SaveHashSet { public static void main(String[] args) { Set<String> set = Collections.synchronizedSet(new HashSet()); for(int i = 1;i<=10;i++) { new Thread(()->{ set.add(UUID.randomUUID().toString().substring(0, 5)); System.out.println(Thread.currentThread().getName()+"=>"+set); },String.valueOf(i)).start(); } } }
2.JUC实现Set的安全(java.util.concurrent 下的类 CopyOnWriteArraySet)
public class JUCSetTest { public static void main(String[] args) { Set<String> set = new CopyOnWriteArraySet<String>(); for(int i = 1;i<=10;i++) { new Thread(()->{ set.add(UUID.randomUUID().toString().substring(0, 5)); System.out.println(Thread.currentThread().getName()+"=>"+set); },String.valueOf(i)).start(); } } }
HashMap的不安全性:
当开启多个线程给HashMap里面加元素的时候,会报Exception: java.util.ConcurrentModificationException
1.使用Collections类里面的静态方法:synchonizedMap
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public class SaveHashMapTest { public static void main(String[] args) { Map<Integer,String> map = Collections.synchronizedMap(new HashMap()); for(int i =1;i<=10;i++) { final int temp = i; new Thread(()->{ map.put(temp, UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=>"+map); },String.valueOf(i)).start(); } } }
2.使用JUC实现hashMap的安全性:java.util.concurrent 下的类ConcurrentHashMap
public class JUCHashMapTest { public static void main(String[] args) { Map<Integer,String> map = new ConcurrentHashMap<>(); for(int i = 1;i<=10;i++) { final int temp = i; new Thread(()->{ map.put(temp, UUID.randomUUID().toString().substring(0, 6)); System.out.println(Thread.currentThread().getName()+"=>"+map); },String.valueOf(i)).start(); } } }
Callable接口:
public interface Callable<V>
返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。 
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。 
1.可以有返回值
2.可以抛出异常
3.call()方法
需要借助于FutureTask 找个类来启动一个线程。
public class FutureTask<V>extends Object implements Runnable,Future <V>,RunnableFuture <V>
可使用 FutureTask 包装 Callable 或 Runnable 对象。因为 FutureTask 实现了 Runnable,
FutureTask(Callable<V> callable) 
          创建一个 FutureTask,一旦运行就执行给定的 Callable。 
FutureTask(Runnable runnable, V result) 
          创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。 
public class TestCallable { public static void main(String[] args) { MyThread callable = new MyThread(); FutureTask futureTask = new FutureTask(callable); try { new Thread(futureTask).start(); String retureResult = (String)futureTask.get(); //获取callable的返回结果 System.out.println(retureResult); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class MyThread implements Callable<String> { @Override public String call() throws Exception { System.out.println("Test Callable"); return "Success"; } }
几个常用的工具类:
java.util.concurrent 
类 CountDownLatch
相当于一个减数器
 
只有当所有的子线程都走完了,才会执行接下来的主线程。
只有当所有的子线程都走完了才会执行:System.out.println("Close the door");
public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(4); for(int i = 1;i<=4;i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+" Get out!"); countDownLatch.countDown();//减少锁存器的计数,如果计数达到零则释放所有等待的线程。 System.out.println(String.valueOf("还剩"+countDownLatch.getCount()));//返回当前计数。 },String.valueOf(i)).start(); } countDownLatch.await();// 当前线程等到锁存器倒计数到零 System.out.println("Close the door"); } }
CyclicBarrier:
java.lang.Object 
java.util.concurrent.CyclicBarrier
public CyclicBarrier(int parties,Runnable barrierAction)
创建一个新的 CyclicBarrier ,当给定数量的参与方(线程)等待它时将跳闸,并且当屏障被触发时执行给定的屏障操作,由进入屏障的最后一个线程执行。 
相当于加数器。
只有执行完设定的子线程才会执行构造方法里面的线程。
public class CyclicBarrierDemo { public static void main(String[] args) { //集齐7颗龙珠召唤神龙 CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{ System.out.println("召唤神龙成功!!"); System.out.println(Thread.currentThread().getName());//最后执行完的子线程 }); for(int i = 1;i<=7;i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+"正在运行"); try { cyclicBarrier.await();//等待所有 parties在此障碍上调用 await } catch (InterruptedException | BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); } },String.valueOf(i)).start(); } } }
软件包 java.util.concurrent 
Class Semaphore
- 
计数信号量。 从概念上讲,信号量保持一组许可。 如果有必要,每个acquire()都会阻止,直到有许可证,然后接受。 每个release()都添加了许可证,可能会释放阻止收购者。 但是,没有使用实际的许可对象;Semaphore只保留可用数量并相应地采取行动。
public class SemaphoreDemo { public static void main(String[] args) { //当需要共享资源的时候会用到 //线程数量: Semaphore semaphore = new Semaphore(3); for(int i = 1;i<=7;i++) { new Thread(()->{ try { semaphore.acquire();//先要得到资源 System.out.println("这是第"+Thread.currentThread().getName()+"线程"); TimeUnit.SECONDS.sleep(2); System.out.println("这是第"+Thread.currentThread().getName()+"线程离开"); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release();//释放资源 } },String.valueOf(i)).start(); } } }
ReentrantReadWriteLock(读写锁)
 

 
public class ReentrantReadWriteLockDemo { public static void main(String[] args) { MyThreadLock myThread = new MyThreadLock(); for(int i = 1;i<=5;i++) { final String temp = String.valueOf(i); new Thread(()->{myThread.set(temp, temp);},String.valueOf(i)).start(); } for(int i = 1;i<=5;i++) { final String temp = String.valueOf(i); new Thread(()->{ myThread.get(temp); },String.valueOf(i)).start(); } } } class MyThread{ public volatile Map<String,String> map = new HashMap<String,String>(); public void set(String key,String value) { System.out.println(Thread.currentThread().getName()+"开始写入"); map.put(key, value); System.out.println(Thread.currentThread().getName()+"完成写入"); } public void get(String key) { System.out.println(Thread.currentThread().getName()+"开始读取"); map.get(key); System.out.println(Thread.currentThread().getName()+"完成读取"); } } class MyThreadLock{ private volatile Map<String,String> map = new HashMap<String,String>(); ReadWriteLock lock = new ReentrantReadWriteLock(); public void set(String key,String value) { lock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName()+"开始写入"); map.put(key, value); System.out.println(Thread.currentThread().getName()+"完成写入"); } catch (Exception e) { e.printStackTrace(); }finally { lock.writeLock().unlock(); } } public void get(String key) { lock.readLock().lock(); try { System.out.println(Thread.currentThread().getName()+"开始读取"); map.get(key); System.out.println(Thread.currentThread().getName()+"完成读取"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ lock.readLock().unlock(); } } }
阻塞队列 BlockingQueue

 
 
什么情况下我们会使用阻塞队列:多线程并发处理,线程池!
学会使用队列:添加、移除
四组API:
1.抛出异常
2.不会抛出异常
3.阻塞等待
4.超时等待
| add/remove(抛出异常) | offer/poll | put/take (阻塞等待) | offer/poll带参数的方法(超时等待) | 
| 如果超过数量,则会抛出异常 java.lang.IllegalStateException: Queue full java.util.NoSuchElementException | 不会抛出异常 数据满了以后offer返回false poll 没有数值了则返回null 
 | put:当数据满了则会一直等待,不会报错,需要try/catch(throws) put没有返回值 take如果没有值了也会一直等待 |  boolean offer(E o, long timeout, TimeUnit unit)  | 
| add:返回值为true/false remove:返回移掉的对象 | offer:返回值为true/false poll :返回移掉的对象 | put:没有返回值 take:返回移掉的对象 | 都有一个contains()方法 | 
| peek()方法可以查看下一个元素,如果没有值返回null,有值返回对象 | peek()方法可以查看下一个元素 | 
public class AddAndRemove {
public static void main(String[] args) { // 设置队列的大小 ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue(3); System.out.println(arrayBlockingQueue.add("1")); System.out.println(arrayBlockingQueue.add("2")); System.out.println(arrayBlockingQueue.add("3")); //System.out.println(arrayBlockingQueue.add("4")); //抛出异常 java.lang.IllegalStateException: Queue full System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove());
//System.out.println(arrayBlockingQueue.remove()); // 抛出异常 java.util.NoSuchElementException
System.out.println(arrayBlockingQueue.peek()); } }
public class OfferAndPoll { public static void main(String[] args) { ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue(3); System.out.println(arrayBlockingQueue.offer(1)); System.out.println(arrayBlockingQueue.offer(1)); System.out.println(arrayBlockingQueue.offer(1)); //System.out.println(arrayBlockingQueue.offer(1));// 不抛出异常,返回false for(Integer i:arrayBlockingQueue) { System.out.println(i); } System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.peek()); //System.out.println(arrayBlockingQueue.poll());// 不抛出异常,返回null
} }
public class PutAndTake { public static void main(String[] args) throws InterruptedException { ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue(3); arrayBlockingQueue.put(1); arrayBlockingQueue.put(2); arrayBlockingQueue.put(2); //arrayBlockingQueue.put(2); //一直等待 阻塞状态 System.out.println("peek:"+arrayBlockingQueue.peek()); System.out.println("contains:"+arrayBlockingQueue.contains(1)); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); //一直等待 阻塞状态
} }
public class DelayOfferAndPoll { public static void main(String[] args) throws InterruptedException { ArrayBlockingQueue arrayBlockQueue = new ArrayBlockingQueue(3); System.out.println(arrayBlockQueue.offer(1, 1, TimeUnit.SECONDS)); System.out.println(arrayBlockQueue.offer(1, 1, TimeUnit.SECONDS)); System.out.println(arrayBlockQueue.offer(1, 1, TimeUnit.SECONDS)); System.out.println(arrayBlockQueue.offer(1, 1, TimeUnit.SECONDS));//false 阻塞一秒 System.out.println(arrayBlockQueue.poll(1,TimeUnit.SECONDS)); System.out.println(arrayBlockQueue.poll(1,TimeUnit.SECONDS)); System.out.println(arrayBlockQueue.poll(1,TimeUnit.SECONDS)); System.out.println(arrayBlockQueue.poll(2,TimeUnit.SECONDS));//null 阻塞一秒 } }
SynchonousQueue(put/take)
没有容量,进去一个元素,必须等待取出来之后,才能再往里面放一个元素。
SynchonousQueue和一般的BlockingQueue不一样,存入一个先先取出来才能再存入
public class SynchronousQueueDemo { public static void main(String[] args) throws InterruptedException { SynchronousQueue<Integer> sq = new SynchronousQueue<Integer>(); new Thread(() -> { try { System.out.println(Thread.currentThread().getName()+"加入元素1"); sq.put(1); System.out.println(Thread.currentThread().getName()+"加入元素2"); sq.put(2); } catch (InterruptedException e) { e.printStackTrace(); } },"T1").start(); new Thread(()->{ try { TimeUnit.SECONDS.sleep(5); System.out.println(Thread.currentThread().getName()+"取出元素"+sq.take()); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName()+"取出元素"+sq.take()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } },"T2").start(); } }
输出结果:
T1加入元素1
T2取出元素1
T1加入元素2
T2取出元素2
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号