多线程
并发编程和ActiveMQ(消息中间件)
16:02:20 2017-11-22
volatile关键字:使多个变量在线程间可见,一致性。
AutomicInteger关键字 原子性
notify唤醒其他线程,不释放锁
wait 进入等待,释放锁。
模仿queue队列
package com.cmos.ngkm.web.controller.basic; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; public class MyQueue { //需要指定上限和下限 private final int minSize = 0; private int maxSize; //需要一个承载元素的集合 private LinkedList<Object> list = new LinkedList<Object>(); //需要一个计数器 private AtomicInteger count = new AtomicInteger(0); //初始化一个对象用于加锁 private final Object lock = new Object(); //构造函数 public MyQueue(int size) { this.maxSize = size; } public void put(Object obj) { synchronized (lock){ //当前容器已经满了 while(count.get()==this.maxSize) { try{ lock.wait(); } catch (Exception e) { e.printStackTrace(); } } list.add(obj); count.incrementAndGet(); //唤醒另一个线程 lock.notify(); System.out.println("新加入元素"+obj); } } public Object take() { Object obj = null; synchronized (lock){ if(count.get()==this.minSize) { try { lock.wait(); }catch (Exception e) { e.printStackTrace(); } } obj = list.removeFirst(); count.decrementAndGet(); lock.notify(); System.out.println("移除元素"+obj); } return obj; } public static void main(String args[]) { final MyQueue myqueue = new MyQueue(5); myqueue.put("a"); myqueue.put("b"); myqueue.put("c"); myqueue.put("d"); myqueue.put("e") ; Thread t1 = new Thread(new Runnable() { @Override public void run() { myqueue.put("f"); myqueue.put("j"); } },"t1"); t1.start(); Thread t2 = new Thread(new Runnable(){ @Override public void run() { myqueue.take(); myqueue.take(); } },"t2"); t2.start(); } }
1.vector和ArrayList(都是对象型数组)
1) Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
2) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
2. Hashtable & HashMap
Hashtable和HashMap它们的性能方面的比较类似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。
3.ArrayList和LinkedList
ArrayList的内部实现是基于内部数组Object[],所以从概念上讲,它更象数组,但LinkedList的内部实现是基于一组连接的记录,所以,它更象一个链表结构,所以,它们在性能上有很大的差别:
从上面的分析可知,在ArrayList的前面或中间插入数据时,你必须将其后的所有数据相应的后移,这样必然要花费较多时间,所以,当你的操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能; 而访问链表中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素地去查找,直到找到所需的元素为止,所以,当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
Vector,HashTable 同步类容器并不支持并发
支持并发容器

concurrentMap通过采用分段的方式减小锁粒度,最多支持16个段(segement),从而支持并发

copyOnWrite容器即写时复制的容器。读和写不同容器,读写分离。
队列
阻塞队列(7种)
一、什么叫阻塞队列?
当队列为满的情况下向队列加数据的线程被阻塞直到队列元素被取出或者当队列为空时相对列取元素的线程被阻塞,直到队列加入数据。
二、阻塞队列有哪几种?
1. ConcurrentLinkedQueue:一个适用于高并发场景下的队列,通过无锁方式实现高并发状态下的高性能。通常ConcurrentLinkedQueue性能好于BlockingQueue。他是一个基于链接节点的无界线程安全队列。该队列的元素遵循先进先出的原则。队列不允许null元素。
2. ArrayBlockingQueue:基于数组的阻塞队列实现,在ArrayBlockingQueue内部维护了一个定长数组,以便缓存队列中的数据对象,其内部没有实现读写分离,也就意味着生产和消费不能完全并行,长度是需要定义的,可以指定先进先出或者先进后出。
3、LinkedBlockingQueue:基于链表的阻塞队列,能够高效处理并发数据。内部采用分离锁的方式(读和写两个锁),从而实现生产者和消费者操作的完全并行运行,是一个无界队列。
4、SynchronousQueue:一种没有缓冲的队列,生产者产生的数据直接会被消费者获取并消费。

5、priorityBlockingQueue:基于优先级的阻塞队列(优先级的判断通过构造函数compator对象来决定,也就是说传入的对象必须实现comparable接口)
package com.cmos.ngkm.web.controller.basic; public class Task implements Comparable<Task>{ private int id; private String name; public void setId(int id) { this.id = id; } public int getId() { return id; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public int compareTo(Task task) { return this.id>task.id ? 1:(this.id<task.id? -1:0); } }
package com.cmos.ngkm.web.controller.basic; import io.swagger.models.auth.In; import java.util.Iterator; import java.util.concurrent.PriorityBlockingQueue; public class MyPriorityQueue { private static PriorityBlockingQueue<Task> pq = new PriorityBlockingQueue<>(); public static void main(String[] args) { Task t1 = new Task(); t1.setId(2); t1.setName("任务一"); pq.put(t1); Task t2 = new Task(); t2.setId(6); t2.setName("任务二"); pq.put(t2); Task t3 = new Task(); t3.setId(3); t3.setName("任务三"); pq.put(t3); System.out.print(pq.poll().getName()); System.out.print(pq.poll().getName()); System.out.print(pq.poll().getName()); } }
6、DelayQueue:带有延迟时间的Queue,队列中的元素只有当延迟的时间到了才能获取到该元素。DelayQueue中的元素必须实现Delayed接口。
package com.cmos.ngkm.web.controller.basic; import java.util.concurrent.DelayQueue; public class WangBa implements Runnable { private DelayQueue<Wangming> delayQueue = new DelayQueue<Wangming>(); public boolean yingye = true; public void shangji(String name,String id,int money) { Wangming man = new Wangming(id,name,money*1000+System.currentTimeMillis()); System.out.print(name+"在"+System.currentTimeMillis()+"上机"); this.delayQueue.add(man); } public void xiaji(Wangming man) { System.out.println(man.getName()+"下机"+"结束时间为:"+man.getEndTime()); } @Override public void run() { while(yingye) { try{ Wangming man = delayQueue.take(); xiaji(man); }catch(Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { System.out.println("开始营业"); WangBa wb = new WangBa(); Thread th = new Thread(wb); th.start(); wb.shangji("甲","123",1); wb.shangji("乙","234",5); wb.shangji("丙","678",9); } }
package com.cmos.ngkm.web.controller.basic; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class Wangming implements Delayed{ //姓名 private String name; //身份证号 private String id; //结束时间 private long endTime; //定义事件工具类 private TimeUnit timeUnit = TimeUnit.SECONDS; public Wangming(String id,String name,long endTime) { this.id=id; this.name=name; this.endTime=endTime; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public long getEndTime() { return endTime; } public void setEndTime(long endTime) { this.endTime = endTime; } @Override public long getDelay(TimeUnit unit) { return endTime-System.currentTimeMillis(); } @Override public int compareTo(Delayed delayed) { Wangming w = (Wangming) delayed; return this.getDelay(this.timeUnit)-delayed.getDelay(this.timeUnit)>0 ? 1:0; } }
阻塞队列的几种常用存取数据方法:
放入数据
1)offer 如果BlockQueue可以加入数据(即容器未满),返回true,否则返回false。
2)put 加入数据如果没有空间,等待取线程取出数据释放空间再加入。
3)add 加入数据空间已满直接报异常。
提取数据
1)poll 取出数据,如果有数据返回该数据,否则返回null
2)take 取出数据没有数据,则线程进入阻塞状态,等待加入数据
3)drainTo 一次性取出队列中的数据,或者固定个数的数据。
浙公网安备 33010602011771号