java多线程总结学习-Queue、容器、单例模式

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 q = new ConcurrentLinkedQueue();
		
		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 aq = new ArrayBlockingQueue(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 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 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 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 pq = new PriorityBlockingQueue();
		
		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{
	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 dq = new DelayQueue();
	
	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)