Hashtable
往里面添加任何对象的时候,都要锁定整个对象
ConcurrentHashMap
默认把整个容器分成16段每一次往里面插入的时候,只锁定16段中的一段。
ConcurrentHashMap就是把锁给细化了,当很多线程往里面插入数据的时候,就可以并发的插入,只锁定当前这一块,而不需要锁定整个对象。它把大锁变成了小锁。
ConcurrentSkipListMap
支持高并发,并且插入数据的时候需要,排序,则需要调跳表map
public class T01_ConcurrentMap {
public static void main(String[] args) {
Map<String, String> map = new ConcurrentHashMap<>();
//Map<String, String> map = new ConcurrentSkipListMap<>(); //高并发并且排序
//Map<String, String> map = new Hashtable<>();
//Map<String, String> map = new HashMap<>(); //Collections.synchronizedXXX
//TreeMap
Random r = new Random();
Thread[] ths = new Thread[100];
CountDownLatch latch = new CountDownLatch(ths.length);
long start = System.currentTimeMillis();
for(int i=0; i<ths.length; i++) {
ths[i] = new Thread(()->{
for(int j=0; j<10000; j++) map.put("a" + r.nextInt(100000), "a" + r.nextInt(100000));
latch.countDown();
});
}
Arrays.asList(ths).forEach(t->t.start());
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
Collection.synchronizedMap(Map<k,v>m)
传入一个不加锁的map返回给你一个加锁的map,所以你拿到的新的容器就已经是加锁了的。
public class T03_SynchronizedList {
public static void main(String[] args) {
List<String> strs = new ArrayList<>();
List<String> strsSync = Collections.synchronizedList(strs);
}
}
CopyOnWriteArrayList
写时复制,写的效率非常低,读的效率非常高。 这个容器往里面添加一个新的元素的时候,它会把这个容器复制一份,然后在后面加一个新的
然后把这个引用加到后面。 有点想数据库读写分离,适用于写的很少,读很多的并发环境。
public class T02_CopyOnWriteList {
public static void main(String[] args) {
List<String> lists =
//new ArrayList<>(); //这个会出并发问题!
//new Vector();
new CopyOnWriteArrayList<>();
Random r = new Random();
Thread[] ths = new Thread[100];
for(int i=0; i<ths.length; i++) {
Runnable task = new Runnable() {
@Override
public void run() {
for(int i=0; i<1000; i++) lists.add("a" + r.nextInt(10000));
}
};
ths[i] = new Thread(task);
}
runAndComputeTime(ths);
System.out.println(lists.size());
}
static void runAndComputeTime(Thread[] ths) {
long s1 = System.currentTimeMillis();
Arrays.asList(ths).forEach(t->t.start());
Arrays.asList(ths).forEach(t->{
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
long s2 = System.currentTimeMillis();
System.out.println(s2 - s1);
}
}
上面的都是map,可以换成set也是试用的。 说到底map和set底层实现都大同小异
Queue
offer:相当于add,但是如果在arraylist中add越界会抛异常
poll:从头上拿一个元素,会删除
peek : 从头上拿一个,不删除
ConcurrentLinkedQueue
无界队列,底层是用链表实现
public class T04_ConcurrentQueue {
public static void main(String[] args) {
Queue<String> strs = new ConcurrentLinkedQueue<>();
for(int i=0; i<10; i++) {
strs.offer("a" + i); //相当于add,但是如果在arraylist中add越界会抛异常
}
System.out.println(strs);
System.out.println(strs.size());
System.out.println(strs.poll()); //从头上拿一个,删
System.out.println(strs.size());
System.out.println(strs.peek()); //从头上拿一个,不删
System.out.println(strs.size());
}
}
BlockingQueue
阻塞试队列,实现了这个接口的容器,天然的就可以形成生产者和消费者模式。
put:添加元素,如果满了,就会等待。
take: 拿一个元素,如果容器空了,就会等待
add : 添加一个元素,如果满了就会抛出异常
offer : 添加一个元素,如果满了不会报异常,当然可不会添加成功,会返回一个boolean类型告诉你是不是添加成功。
LinkedBlockingQueue
无界队列,底层链表实现。
public class T05_LinkedBlockingQueue {
static BlockingQueue<String> strs = new LinkedBlockingQueue<>();
static Random r = new Random();
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
strs.put("a" + i); //如果满了,就会等待
TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "p1").start();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
for (;;) {
try {
System.out.println(Thread.currentThread().getName() + " take -" + strs.take()); //如果空了,就会等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "c" + i).start();
}
}
}
ArrayBlockingQueue
有界队列,底层数组实现。
public class T06_ArrayBlockingQueue {
static BlockingQueue<String> strs = new ArrayBlockingQueue<>(10);
static Random r = new Random();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
strs.put("a" + i);
}
strs.put("aaa"); //满了就会等待,程序阻塞
//strs.add("aaa");
//strs.offer("aaa");
//strs.offer("aaa", 1, TimeUnit.SECONDS);
System.out.println(strs);
}
}
TransferQueue
消费者线程先启动,生产者生产一个东西的时候,不是往里扔,首先去找有没有消费者,如果有消费者就直接给消费者。
TransferQueue有一个自身的方法transfer,如果没有消费者,调用transfer,那么就会在这个地方进行阻塞。 主要用于高并发场景
public class T08_TransferQueue {
public static void main(String[] args) throws InterruptedException {
LinkedTransferQueue<String> strs = new LinkedTransferQueue<>();
/*new Thread(() -> {
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();*/
//strs.transfer("aaa");
strs.put("aaa");
new Thread(() -> {
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
SynchronusQueue
同步Queue, 是一种特殊的TransferQueue,是容器量为0的queue。 来的任何东西,消费者必须马上消费,如果不消费就阻塞。
这地方只能调用put,不能调用add。put在这里是阻塞等待消费者进行消费。
public class T09_SynchronusQueue { //容量为0
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> strs = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
strs.put("aaa"); //阻塞等待消费者消费
//strs.add("aaa");
System.out.println(strs.size());
}
}
DelayQueue
执行定时人任务,无界队列。 每一个元素都记录着还有多长时间才可以被消费者来拿。 这个队列默认是排好顺序的,等待时间最长的在最前面,先往外拿。
public class T07_DelayQueue {
static BlockingQueue<MyTask> tasks = new DelayQueue<>();
static Random r = new Random();
static class MyTask implements Delayed {
long runningTime;
MyTask(long rt) {
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 "" + runningTime;
}
}
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
MyTask t1 = new MyTask(now + 1000);
MyTask t2 = new MyTask(now + 2000);
MyTask t3 = new MyTask(now + 1500);
MyTask t4 = new MyTask(now + 2500);
MyTask t5 = new MyTask(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());
}
}
}
支持高并发,并且插入数据的时候需要,排序,则需要调跳表map
public class T01_ConcurrentMap {
public static void main(String[] args) {
Map<String, String> map = new ConcurrentHashMap<>();
//Map<String, String> map = new ConcurrentSkipListMap<>(); //高并发并且排序
//Map<String, String> map = new Hashtable<>();
//Map<String, String> map = new HashMap<>(); //Collections.synchronizedXXX
//TreeMap
Random r = new Random();
Thread[] ths = new Thread[100];
CountDownLatch latch = new CountDownLatch(ths.length);
long start = System.currentTimeMillis();
for(int i=0; i<ths.length; i++) {
ths[i] = new Thread(()->{
for(int j=0; j<10000; j++) map.put("a" + r.nextInt(100000), "a" + r.nextInt(100000));
latch.countDown();
});
}
Arrays.asList(ths).forEach(t->t.start());
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
传入一个不加锁的map返回给你一个加锁的map,所以你拿到的新的容器就已经是加锁了的。
public class T03_SynchronizedList {
public static void main(String[] args) {
List<String> strs = new ArrayList<>();
List<String> strsSync = Collections.synchronizedList(strs);
}
}
CopyOnWriteArrayList
写时复制,写的效率非常低,读的效率非常高。 这个容器往里面添加一个新的元素的时候,它会把这个容器复制一份,然后在后面加一个新的
然后把这个引用加到后面。 有点想数据库读写分离,适用于写的很少,读很多的并发环境。
public class T02_CopyOnWriteList {
public static void main(String[] args) {
List<String> lists =
//new ArrayList<>(); //这个会出并发问题!
//new Vector();
new CopyOnWriteArrayList<>();
Random r = new Random();
Thread[] ths = new Thread[100];
for(int i=0; i<ths.length; i++) {
Runnable task = new Runnable() {
@Override
public void run() {
for(int i=0; i<1000; i++) lists.add("a" + r.nextInt(10000));
}
};
ths[i] = new Thread(task);
}
runAndComputeTime(ths);
System.out.println(lists.size());
}
static void runAndComputeTime(Thread[] ths) {
long s1 = System.currentTimeMillis();
Arrays.asList(ths).forEach(t->t.start());
Arrays.asList(ths).forEach(t->{
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
long s2 = System.currentTimeMillis();
System.out.println(s2 - s1);
}
}
上面的都是map,可以换成set也是试用的。 说到底map和set底层实现都大同小异
Queue
offer:相当于add,但是如果在arraylist中add越界会抛异常
poll:从头上拿一个元素,会删除
peek : 从头上拿一个,不删除
ConcurrentLinkedQueue
无界队列,底层是用链表实现
public class T04_ConcurrentQueue {
public static void main(String[] args) {
Queue<String> strs = new ConcurrentLinkedQueue<>();
for(int i=0; i<10; i++) {
strs.offer("a" + i); //相当于add,但是如果在arraylist中add越界会抛异常
}
System.out.println(strs);
System.out.println(strs.size());
System.out.println(strs.poll()); //从头上拿一个,删
System.out.println(strs.size());
System.out.println(strs.peek()); //从头上拿一个,不删
System.out.println(strs.size());
}
}
BlockingQueue
阻塞试队列,实现了这个接口的容器,天然的就可以形成生产者和消费者模式。
put:添加元素,如果满了,就会等待。
take: 拿一个元素,如果容器空了,就会等待
add : 添加一个元素,如果满了就会抛出异常
offer : 添加一个元素,如果满了不会报异常,当然可不会添加成功,会返回一个boolean类型告诉你是不是添加成功。
LinkedBlockingQueue
无界队列,底层链表实现。
public class T05_LinkedBlockingQueue {
static BlockingQueue<String> strs = new LinkedBlockingQueue<>();
static Random r = new Random();
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
strs.put("a" + i); //如果满了,就会等待
TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "p1").start();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
for (;;) {
try {
System.out.println(Thread.currentThread().getName() + " take -" + strs.take()); //如果空了,就会等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "c" + i).start();
}
}
}
有界队列,底层数组实现。
public class T06_ArrayBlockingQueue {
static BlockingQueue<String> strs = new ArrayBlockingQueue<>(10);
static Random r = new Random();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
strs.put("a" + i);
}
strs.put("aaa"); //满了就会等待,程序阻塞
//strs.add("aaa");
//strs.offer("aaa");
//strs.offer("aaa", 1, TimeUnit.SECONDS);
System.out.println(strs);
}
}
TransferQueue
消费者线程先启动,生产者生产一个东西的时候,不是往里扔,首先去找有没有消费者,如果有消费者就直接给消费者。
TransferQueue有一个自身的方法transfer,如果没有消费者,调用transfer,那么就会在这个地方进行阻塞。 主要用于高并发场景
public class T08_TransferQueue {
public static void main(String[] args) throws InterruptedException {
LinkedTransferQueue<String> strs = new LinkedTransferQueue<>();
/*new Thread(() -> {
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();*/
//strs.transfer("aaa");
strs.put("aaa");
new Thread(() -> {
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
SynchronusQueue
同步Queue, 是一种特殊的TransferQueue,是容器量为0的queue。 来的任何东西,消费者必须马上消费,如果不消费就阻塞。
这地方只能调用put,不能调用add。put在这里是阻塞等待消费者进行消费。
public class T09_SynchronusQueue { //容量为0
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> strs = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
strs.put("aaa"); //阻塞等待消费者消费
//strs.add("aaa");
System.out.println(strs.size());
}
}
DelayQueue
执行定时人任务,无界队列。 每一个元素都记录着还有多长时间才可以被消费者来拿。 这个队列默认是排好顺序的,等待时间最长的在最前面,先往外拿。
public class T07_DelayQueue {
static BlockingQueue<MyTask> tasks = new DelayQueue<>();
static Random r = new Random();
static class MyTask implements Delayed {
long runningTime;
MyTask(long rt) {
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 "" + runningTime;
}
}
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
MyTask t1 = new MyTask(now + 1000);
MyTask t2 = new MyTask(now + 2000);
MyTask t3 = new MyTask(now + 1500);
MyTask t4 = new MyTask(now + 2500);
MyTask t5 = new MyTask(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());
}
}
}