java多线程总结学习-Queue、容器、单例模式
2017-10-13 17:24
459 查看
1、单例模式支持多线程
单例模式:常用的两种模式:饿汉模式 懒汉模式,但这两种模式在多线程应用场景并不安全为了适用于多线程,保障线程安全,用下面两种:double check instance、static inner class
(1)static inner class
package thread;/**
* 单例模式,保障线程安全
* static inner class
* 静态内部类形式
*/
public class SingleInner {
private static class Singleton{
private static Singleton single = new Singleton();
}
public static Singleton getInstance(){
return Singleton.single;
}
}
(2)double check instance
public class Singleton{ //私有静态实例,防止被引用 private static Singleton instance = null; //私有构造方法,防止被实例化 private Singleton(){ } private static synchronized void syncInit(){ if(instance == null){ instance = new Singleton(); } } public static Singleton getInstance(){ if(instance == null){ syncInit(); } return instance; } }
2、同步类容器、并发类容器
同步类:vector hashTable(底层自带synchronid修饰,实现了同步,但是影响并发效率)并发类:Queue、concurrentMap、LinkedBlockingQueue、CopyOnWrite
(1)ConcurrentHashMap:
用段segment划分多个段,每个段相当于hashTable,有对应锁,最高支持16个段每个线程来的时候,访问不同的段
作用:减少锁粒度,减少锁竞争
底层大量使用volatile关键字,实现共享变量
(2)Copy-On-Write(COW)
CopyOnWriteArrayList和CopyOnWriteArraySet写时复制的容器、实现读写分离
当一个线程操作(增删改)容器时,不直接操作该容器,而是复制一个一模一样的容器进行操作,操作完成后,将原容器的指针指向复制的容器。
当有其他线程进行读时,直接读取原容器,实现读写相分离
应用场景:读多写少的时候
3、并发queue
ConcurentLinkedQueue:非阻塞的,性能高,高并发BlockingQueue:阻塞的
ConcurentLinkedQueue:
先进先出,头是最先的,尾是最近的,不允许有null值
add() offer()加入元素,在ConcurentLinkedQueue里没区别
poll() peek() 取头元素,前者删除元素,后者不删
BlockingQueue:,阻塞的
1、ArrayBlockingQueue,基于数组、有界队列,阻塞的
2、LinkedBlockingQueue 无界队列,阻塞的
3、synchronousQueue:没有缓冲的队列,不能添加元素
4、priorityBlockingQueue:基于优先级的阻塞队列,传入队列的对象必须实现comparable接口 不遵循先进先出
5、DelayQueue:元素必须实现delayed接口,元素必须到达延迟时间时,才会被取出
(1)ConcurentLinkedQueue
package queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * ConcurrentLinkedQueue非阻塞的,性能高,高并发 * 先进先出,头是最先的,尾是最近的,不允许有null值 * add() offer()加入元素,在ConcurentLinkedQueue里没区别 * poll() peek() 取头元素,前者删除元素,后者不删 */ public class UseConcurrentQueue { public static void main(String[] args) { ConcurrentLinkedQueue<String> q = new ConcurrentLinkedQueue<String>(); q.add("a"); q.add("b"); q.add("c"); q.add("d"); q.offer("e"); q.offer("f"); System.out.println(q.size()); System.out.println(q.poll()); System.out.println(q.size()); System.out.println(q.peek()); System.out.println(q.size()); } }
(2)BlockingQueue(ArrayBlockingQueue、linkedBlockingQueue、SynchronousQueue)
package queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.SynchronousQueue; /** * BlockingQueue:阻塞的 * ArrayBlockingQueue:基于数组的,有界的 * linkedBlockingQueue:无界的,在初始化时,给定长度,则是有界的,不给定长度,则是无界的 * SynchronousQueue:没有容量的队列,take()方法会进行阻塞,执行过take后,可以进行add,直接add会报错,因为没容量 * */ public class UseBlockingQueue { public static void main(String[] args) throws Exception{ //ArrayBlockingQueue ArrayBlockingQueue<String> aq = new ArrayBlockingQueue<String>(5); aq.add("a"); aq.add("b"); aq.put("c"); aq.put("d"); aq.offer("e"); aq.offer("f"); System.out.println("ArrayBlockingQueue:"+aq); //linkedBlockingQueue LinkedBlockingQueue<String> lq = new LinkedBlockingQueue<>(); lq.add("a"); lq.add("b"); lq.put("c"); lq.put("d"); lq.offer("e"); lq.offer("f"); System.out.println("LinkedBlockingQueue无界:"+lq); LinkedBlockingQueue<String> lq2 = new LinkedBlockingQueue<>(4); lq2.add("a"); lq2.add("b"); lq2.put("c"); lq2.put("d"); lq2.offer("e"); lq2.offer("f"); System.out.println("LinkedBlockingQueue有界:"+lq2); //synchronousQueue final SynchronousQueue<String> sq = new SynchronousQueue<>(); //sq.add("a"); //会报错java.lang.IllegalStateException: Queue full Thread t1 = new Thread(new Runnable(){ @Override public void run() { try { sq.take(); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); Thread t2 = new Thread(new Runnable(){ @Override public void run() { sq.add("a"); System.out.println("SynchronousQueue:"+sq); } }); t2.start(); } }
(3)PriorityBlockingQueue。模拟场景:当有任务时,会根据任务ID,按照优先级,进行释放
package queue;import java.util.concurrent.PriorityBlockingQueue;
import queue.priority.Task;
/**
* PriorityBlockingQueue:优先级队列
* 队列里的元素必须继承comparable接口,并实现方法
* 当对队列进行take操作是,队列会根据优先级排序(不遵循先进先出)
*
*/
public class UsePriorityBlockingQueue {
public static void main(String[] args) throws Exception{
PriorityBlockingQueue<Task> pq = new PriorityBlockingQueue<Task>();
Task t1 = new Task();
t1.setId(1);
t1.setName("任务1");
Task t2 = new Task();
t2.setId(4);
t2.setName("任务2");
Task t3 = new Task();
t3.setId(3);
t3.setName("任务3");
pq.add(t1);
pq.add(t2);
pq.add(t3);
System.out.println("容器:"+pq.toString());
System.out.println(pq.take().getId());
System.out.println("容器:"+pq.toString());
System.out.println(pq.take().getId());
System.out.println(pq.take().getId());
}
}
package queue.priority; 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 o) { return this.id > o.id ? 1 : (this.id > o.id ? -1 : 0); } public String toString(){ return this.id + "," + this.name; } }
运行结果:
容器:[1,任务1, 4,任务2, 3,任务3]
1
容器:[3,任务3, 4,任务2]
3
4
(4)DelayQueue,模拟场景,网吧上机,到时间下机
package queue; import java.util.concurrent.DelayQueue; import queue.delay.Wangmin; /** * DelayQueue:延迟队列 * 元素必须实现delayed接口 * 元素必须到达延迟时间时,才会被取出 */ public class UseDelayQueue implements Runnable{ DelayQueue<Wangmin> dq = new DelayQueue<Wangmin>(); public void shangji(int id, String name, int money){ Wangmin wm = new Wangmin(id,name,1000*money+System.currentTimeMillis()); dq.add(wm); System.out.println("网民:"+name+"开始上机,上机时间"+money+"秒"); } public void xiaji(Wangmin wm){ System.out.println("网民:"+wm.getName()+"下机。。。"); } @Override public void run() { while(true){ try { Wangmin wm = dq.take(); xiaji(wm); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { UseDelayQueue udq = new UseDelayQueue(); Thread t = new Thread(udq); t.start(); udq.shangji(1,"张三",1); udq.shangji(2,"李四",10); udq.shangji(3,"王五",5); } }
package queue.delay; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; /** * 网民 * 实现了Delayed接口 * 需要实现getDelay、compareTo方法 */ public class Wangmin implements Delayed{ private int id; private String name; private long endtime; private TimeUnit timeUnit = TimeUnit.SECONDS;//时间单位,秒 //构造方法 public Wangmin(int id, String name, long endtime){ this.id=id; this.name = name; this.endtime = endtime; } @Override public int compareTo(Delayed delay) { Wangmin w = (Wangmin)delay; return this.getDelay(this.timeUnit) > w.getDelay(this.timeUnit) ? 1 : 0; } @Override public long getDelay(TimeUnit arg0) { return endtime - System.currentTimeMillis(); } 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; } public long getEndtime() { return endtime; } public void setEndtime(long endtime) { this.endtime = endtime; } }
运行结果:
网民:张三开始上机,上机时间1秒
网民:李四开始上机,上机时间10秒
网民:王五开始上机,上机时间5秒
网民:张三下机。。。
网民:王五下机。。。
网民:李四下机。。。
相关文章推荐
- 黑马程序员--Java学习日记之总结复习(多线程和设计模式)
- Java容器学习笔记(二) Set接口及其实现类的相关知识总结
- java的设计模式,学习心得总结-工厂模式
- Java多线程学习总结(二)
- java多线程学习总结之一:基础原理
- Java容器学习笔记(二) Set接口及其实现类的相关知识总结
- Java 多线程学习总结3
- Java多线程总结之聊一聊Queue
- JAVA多线程与并发学习总结
- Java设计模式学习心得总结
- 转 java多线程学习总结
- 黑马程序员之JAVA学习笔记:多线程学习大总结
- java多线程学习总结之二:线程状态的转换
- Java学习总结之第十三章 多线程
- Java多线程学习总结(一)
- Java多线程总结之线程安全队列Queue
- Java 多线程学习总结3.1
- JAVA多线程与并发学习总结
- Java 多线程学习总结6