Hashmaphashtable 线程安全的 装的都是Key,Value对,一对一对的。
hashtable 如何保证线程安全的 基本所有方法都添加了synchronized 所以效率很慢
SynchronizedHashMapHashmap 线程不安全的 也是键值对存储
因为Hashtable 全程加锁所以效率很慢 在不需要保证线程安全的情况下就出现了Hashmap
ConcurrentHashMapSynchronizedHashMap 基本就是给HashMap我们手动加锁,它的源码自己做了一个Object,然后每次都是SynchronizedObject,严格来讲他和那个Hashtable效率上区别不大。
Vector发展 VectorConcurrentHashMap是多线程里面真正用的,以后我们多线程用的基本就是它
这个ConcurrentHashMap提高效率主要提高在读上面,由于它往里插的时候内部又做了各种各样的判断,本来是链表的,到8之后又变成了红黑树,然后里面又做了各种各样的cas的判断,所以他往里插的数据是要更低一些的。
LinkedListVector Hashtable 一样全程加锁的,存储格式就是数组也就不多说
LinkedList虽然你用了这个加锁的容器了,由于在你调用这个并发容器的时候,你是调用了其中的两个原子方法,所以你在外层还得在加一把锁synchronized(tickets),继续判断size,然后不断的remove 如下操作比较麻烦
public static void main(String[] args) {
static List tickets = new LinkedList<>();
for(int i=0; i<1000; i++) tickets.add(i);
for(int i=0; i<10; i++) {
new Thread(()->{
while(true) {
synchronized(tickets) {
if(tickets.size() <= 0) break;
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tickets.remove(0));
}
}
}).start();
}
}
Queue
CopyOnWrit效率最高的就是这个Queue,这是最新的一个接口,他的主要目标就是为了高并发用的,就是为了多线程用的。所以,以后考虑多线程这种单个元素的时候多考虑Queue。如ConcurrentLinkedQueue
Queue queue= new ConcurrentLinkedQueue<>();
tickets.poll() 在里面取值 这个方法就是线程安全的
Queue和List的区别到底在哪里,主要就在这里,添加了offer、peek、poll、put、take这些个对线程友好的或者阻塞,或者等待方法。
几个常用的Queue BlockingQueue这个类叫CopyOnWrite。CopyOnWriteList、CopyOnWriteSet有两个。CopyOnWrite的意思叫写时复制。
这个CopyOnWrite解释一下,你通过这个名字进行分析一下,当Write的时候我们要进行复制,写时复制,写的时候进行复制。这个原理非常简单,当我们需要往里面加元素的时候你把里面的元素得复制出来。因为写的时候需要复制且有一系列操作所以用于读多写少的情况。
LinkedBlockingQueueBlockingQueue的概念重点是在Blocking上,Blocking阻塞,Queue队列,是阻塞队列。他提供了一系列的方法,我们可以在这些方法的基础之上做到让线程实现自动的阻塞。
offer 方法 offer添加数据 跟之前add作用一样不同在于offer返回值是布尔类型告诉你是否添加成功 add则是会报错
poll 方法 peek的概念是去取并不是让你remove掉,poll是取并且remove掉,而且也是线程安全的。
ArrayBlockingQueueLinkedBlockingQueue 是一个又链表实现的BlockingQueue 链表就是无界的
DelayQueueArrayBlockingQueue是有界的,你可以指定它一个固定的值10,它容器就是10,那么当你往里面扔容器的时候,一旦他满了这个put方法就会阻塞住。然后你可以看看用add方法满了之后他会报异常。offer用返回值来判断到底加没加成功,offer还有另外一个写法你可以指定一个时间尝试着往里面加1秒钟,1秒钟之后如果加不进去它就返回了。
BlockingQueue strs = new ArrayBlockingQueue<>(10);
strs.offer(“aaa”, 1, TimeUnit.SECONDS);
DelayQueue可以实现 按照指定规则来排序,下面DelayQueue能实现按照在里面等待的时间来进行排序。这里我们new了一个DelayQueue,他是BlockingQueue的一种也是用于阻塞的队列,这个阻塞队列装任务的时候要求你必须实现Delayed接口,Delayed往后拖延推迟,Delayed需要做一个比较compareTo,最后这个队列的实现,这个时间等待越短的就会有优先的得到运行,所以你需要做一个比较 ,这里面他就有一个排序了,这个排序是按时间来排的,所以去做好,哪个时间返回什么样的值,不同的内容比较的时候可以按照时间来排序。
package com.mashibing.juc.c_025;
import java.util.Calendar;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class DelayQueue {
static BlockingQueue tasks = new DelayQueue<>();
static Random r = new Random();
//实现接口
static class MyTask implements Delayed {
String name;
long runningTime;
//构造方法
MyTask(String name, long rt) {
this.name = name;
this.runningTime = rt;
}
//判断规则
@Override
public int compareTo(Delayed o) {
if(this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS))
return -1;
else if(this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS))
return 1;
else
return 0;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(runningTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public String toString() {
return name + " " + runningTime;
}
}
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
MyTask t1 = new MyTask("t1", now + 1000);
MyTask t2 = new MyTask("t2", now + 2000);
MyTask t3 = new MyTask("t3", now + 1500);
MyTask t4 = new MyTask("t4", now + 2500);
MyTask t5 = new MyTask("t5", now + 500);
tasks.put(t1);
tasks.put(t2);
tasks.put(t3);
tasks.put(t4);
tasks.put(t5);
System.out.println(tasks);
for(int i=0; i<5; i++) {
System.out.println(tasks.take());
}
}
}
SynchronousQueue
SynchronousQueue容量为0,就是这个东西它不是用来装内容的,SynchronousQueue是专门用来两个线程之间传内容的 如下就是将内容交给线程内输出 然后strs.size()时候是没有的
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
public class SynchronousQueue { //容量为0
public static void main(String[] args) throws InterruptedException {
BlockingQueue strs = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(strs.take());//消费内容
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
strs.put("aaa"); //阻塞等待消费者消费
System.out.println(strs.size());
}
}
TransferQueue
TransferQueue传递,实际上是前面这各种各样Queue的一个组合,它可以给线程来传递任务,以此同时不像是SynchronousQueue只能传递一个,TransferQueue做成列表可以传好多个。
它添加了一个方法叫transfer,如果我们用put就相当于一个线程来了往里一装它就走了。transfer就是装完在这等着,阻塞等有人把它取走我们才会继续执行的事情。
import java.util.concurrent.LinkedTransferQueue;
public class TransferQueue{
public static void main(String[] args) throws InterruptedException {
LinkedTransferQueue strs = new LinkedTransferQueue<>();
new Thread(() -> {
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
strs.transfer("aaa");
System.out.println("继续执行");
}
}



