/** * 同步类容器都是线程安全的,但在某些场景下可能需要加锁来保护复合操作,复合操作如: * 迭代(反复访问元素,遍历完容器中所有的元素),跳转(根据指定的顺序找到当前元素的 * 下一个元素),以及条件运算。这些复合操作在多线程并发地修改容器时,可能会表现出意 * 外的行为,最经典的便是ConcurrentModificationException,原因是当容器迭代的过程中, * 被并发的修改了内容,这是由于早期迭代器设计的时候并没有考虑并发修改的问题。 * * 同步类容器:如古老的Vector,HashTable.这些容器的同步功能其实都是有JDK的Collections.synchronized*** * 等工厂方法去创建实现的。其底层的机制无非就是用传统的synchronized关键字对每个公用的方法 * 都进行同步,使得每次只能有一个线程访问容器的状态。这很明显不满足我们今天互联网时代高并 * 发的需求,在保证线程安全的同时,也必须要有足够好的性能。
*/
import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Vector; public class Tickets { public static void main(String[] args) { //初始化火车票池并添加火车票:避免线程同步可采用Vector替代ArrayList,HashTable替代HashMap final Vector<String> tickets = new Vector<String>(); // Map<String,String> map = Collections.synchronizedMap(new HashMap<String,String>()); for (int i = 1 ; i <= 1000 ; i++){ tickets.add("火车票" + i); } for (int i = 1; i <= 10 ; i++){ new Thread("线程" + i){ public void run(){ while(true){ if (tickets.isEmpty()) break; System.out.println(Thread.currentThread().getName() + "---" + tickets.remove(0)); } } }.start(); } } }
/** * jdk5.0以后提供了多种并发类容器来替代同步类容器从而改善性能。同步类容器的状态都是 * 串行化的,他们虽然实现了线程安全,但是严重降低了并发性,在多线程环境时,严重降低 * 了应用程序的吞吐量。 * 并发类容器是专门正对并发设计的,使用ConcurrentHashMap来代替给予散列的传统的 * HashTable,而且在ConCurrentHashMap中,添加了一些常见的复合操作的支持。以及使用了 * CopyOnWriteArrayList代替Vector,并发的CopyOnWriteArraySet,以及并发的Queue, * ConcurrentLinkedQueue和LinkedBlockingQueue,前者是高性能的队列,后者是以阻塞形式的 * 队列,具体实现Queue还有很多,例如ArrayBlockingQueue,PriorityBlockingQueue, * SynchronousQueue等。 */
/** * ConcurrentMap接口下有两个重要的实现: * ConcurrentHashMap * ConcurrentSkipListMap(支持并发排序功能,弥补ConCurrentHashMap) * ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是 * 一个小的HashTable,它们有自己的锁,只要多个修改操作发生在不同的段上,他们 * 就可以并发进行。把一个整体分成16个段(Segment),也就是最高支持16个线程的并发 * 修改操作。这也是在多线程场景时减少锁的粒度从而降低锁竞争的一种方案。并且代码中 * 大多共享变量使用volatile关键字声明,目的是第一时间获取修改的内容,性能非常好 */
/** * Copy-On-Write简称COW,是一种用于程序设计中的优化策略。 * JDK里的COW容器有两种:CopyOnWriteArrayList和CopyOnWriteArraySet, * COW容器非常有用,可以在非常多的开发场景中使用到。 * 什么是CopyOnWrite容器? * CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候, * 不直接往当前容器添加,而是先将当前容器进行copy,复制出一个新的容器,然后新的 * 容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是 * 我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何 * 元素,所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。 */
/** * 在并发队列上JDK提供了两套实现,一个是以ConcurrentLinkedQueue为代表的高性能队列, * 一个是以BlockingQueue接口为代表的阻塞队列,无论哪种都继承自Queue * Queue * AbstractQueue * AsLIFOQueue * ConcurrentLinkedQueue * BlockingQueue * ArrayBlockingQueue * DelayedWorkQueue * DelayQueue * LinkedBlockingQueue * PriorityBlockingQueue * SynchronousQueue * BlockingDeque * LinkedBlockingDeque * TransferQueue * LinkedTransferQueue * Deque */
/** * ConcurrentLinkedQueue:是一个适用于高并发场景下的队列,通过无锁的方式,实现了 * 高并发状态下的高性能,通常ConcurrentLinkedQueue性能好于BlockingQueue.它是一个 * 基于链接节点的无界线程安全队列。该队列的元素遵循先进先出的原则,头是最先加入的, * 尾是最近加入的,该队列不允许有null元素。 * ConcurrentLinkedQueue重要方法: * add()和offer()都是加入元素的方法(在ConcurrentLinkedQueue中,这两个方法没有任何区别) * poll()和peek()都是取头元素节点,区别在于前者会删除元素,后者不会。 */
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** * ArrayBlockingQueue:基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定常数组, * 以便缓存队列中的数据对象,其内部没实现读写分离,也就意味着生产和消费不能完全并行,长度 * 是需要定义的,可以指定先进先出或者先进后出,也叫有界队列,在很多场合非常适合使用。 * * LinkedBlockingQueue:基于链表的阻塞队列,同ArrayBlockingQueue类似,其内部也维持着一个数据 * 缓冲队列(该队列由一个链表构成),LinkedBlockingQueue之所以能够高效的处理并发数据,是因为 * 其内部实现采用分离锁(读写分离两个锁),从而实现生产者和消费者操作的完全并行运行,他是一个 * 无界队列。 * * SynchronousQueue:一种没有缓冲的队列,生产者产生的数据直接会被消费者获取并消费。 * * PriorityBlockingQueue:基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来 * 决定,也就是说传入队列的对象必须实现Comparable接口),在实现PriorityBlockingQueue时,内 * 部控制线程同步的锁采用的是公平锁,他也是一个无界的队列。 * * DelayQueue:带有延迟时间的Queue,其中的元素只有当其指定的延迟时间到了,才能够从队列中获取 * 到该元素。DelayQueue中的元素必须实现Delayed接口,DelayQueue是一个没有大小限制的队列,应 * 用场景很多,比如对缓存超时的数据进行移除,任务超时处理,空闲连接的关闭等等。 */ public class UseQueue { public static void main(String[] args) throws InterruptedException { /*ArrayBlockingQueue<String> array = new ArrayBlockingQueue<String>(5); array.put("a"); array.put("b"); array.put("c"); array.put("d"); array.put("e"); array.put("f"); System.out.println(array.offer("a",3,TimeUnit.SECONDS));*/ final SynchronousQueue<String> q = new SynchronousQueue<String>(); // q.add("11"); /** * Exception in thread "main" java.lang.IllegalStateException: Queue full * at java.util.AbstractQueue.add(AbstractQueue.java:98) * at cn.fenghuo.jiqing.util.sock.UseQueue.main(UseQueue.java:42) */ Thread t1 = new Thread(new Runnable() { public void run() { try { System.out.println("t1准备!"); System.out.println(q.take()); } catch (InterruptedException e) { e.printStackTrace(); } } },"t1"); t1.start(); TimeUnit.SECONDS.sleep(2); Thread t2 = new Thread(new Runnable() { public void run() { System.out.println("准备添加!"); q.add("xixihaha"); } },"t2"); t2.start(); } }
public class Task implements Comparable<Task>{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int compareTo(Task task) { return this.id > task.id ? 1 : (this.id < task.id ? -1 : 0); } @Override public String toString() { return this.id + "," + this.name; } }
import java.util.concurrent.PriorityBlockingQueue; public class UsePriorityBlockingQueue { public static void main(String[] args) throws InterruptedException { PriorityBlockingQueue<Task> q = new PriorityBlockingQueue<Task>(); Task t1 = new Task(); t1.setId(3); t1.setName("id = 3"); Task t2 = new Task(); t2.setId(4); t2.setName("id = 4"); Task t3 = new Task(); t3.setId(1); t3.setName("id = 1"); q.add(t1); q.add(t2); q.add(t3); System.out.println("容器 : " + q); System.out.println(q.take().getId()); System.out.println("容器 : " + q); System.out.println(q.take().getId()); System.out.println(q.take().getId()); } }
import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class Wangmin implements Delayed { private String id; private String name; private long endTime; private TimeUnit timeUnit = TimeUnit.SECONDS; public Wangmin(String name,String id,long endTime){ this.name = name; this.id = id; this.endTime = endTime; } public long getEndTime() { return endTime; } public void setEndTime(long endTime) { this.endTime = endTime; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 用来判断是否到了截止时间 * @param unit * @return */ @Override public long getDelay(TimeUnit unit) { return endTime - System.currentTimeMillis(); } /** * 相互比较排序用 * @param o * @return */ @Override public int compareTo(Delayed o) { Wangmin w = (Wangmin)o; return this.getDelay(this.timeUnit) - w.getDelay(this.timeUnit) > 0 ? 1 : 0; } }
import java.util.concurrent.DelayQueue; public class Wangba implements Runnable { private DelayQueue<Wangmin> queue = new DelayQueue<Wangmin>(); public boolean yinye = true; public void shangji(String name,String id,int money){ Wangmin man = new Wangmin(name,id,1000 * money + System.currentTimeMillis()); System.out.println("网民" + man.getName() + " 身份证" + man.getId() + "交钱" + money + "块,开始上机。。。"); this.queue.add(man); } public void xiaji(Wangmin man){ System.out.println("网名" + man.getName() + " 身份证" + man.getId() + "时间到下机。。。"); } @Override public void run() { while(yinye){ try { Wangmin man = queue.take(); xiaji(man); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { try{ System.out.println("网吧开始营业"); Wangba siyu = new Wangba(); Thread shangwang = new Thread(siyu); shangwang.start(); siyu.shangji("路人甲","123",1); siyu.shangji("路人乙","234",10); siyu.shangji("路人丙","345",5); }catch (Exception ex){ ex.printStackTrace(); } } }