1、同步容器类
1、Vector
List实现类中包含Vector和ArrayList,都是通过数组实现的。
Vector:是线程安全的,因为方法都加了锁的,sychroinzed。因此他访问的时候耗费的时间
更多,效率低。
Vector内部实现原理 add方法
ArrayList实现原理
2、HashTable
HashMap是线程不安全的,HashTable是线程安全的。加入了锁
HashMap允许null值或键传入。
HashTable是线程安全的,但是效率非常低,因为里面要做锁的资源的竞争。
注意:因为方法是加了sychronized方法的。
多线程共享一个HashTable,每次只能有一个线程去操作这个hashTable
3、sychronizedMap
sychronizedMap:是将线程不安全的集合,变成线程安全的集合。
4、JDK1.5之后发明了ConcurrentHashMap来替代HashTable。
ConcurrentHashMap:实现原理是使用分段锁来实现的,其是以16段分段
底层操作:是将一个整体拆分成多个小的HashTable 默认分成16段。
如图:
5、CountDownLatch实现类似计数的功能。
CountDownLatch: 实现类似计数的功能, 比如有个任务A
它要等待其他4 个任务执行完毕后再执行,此时可以使用CountDownLatch
代码演示
package com.leeue.cn;
import java.util.concurrent.CountDownLatch;
/**
*
* @classDesc: 功能描述:(CountDownLatch 实现类似计数的功能, 比如有个任务A 它
* 要等待其他4 个任务执行完毕后再执行,此时可以使用CountDownLatch)
* @author:<a href="[email protected]">李月</a>
* @Version:v1.0
* @createTime:2018年7月23日 下午1:23:33
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//定义个计数器
CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是子线程1开始执行任务");
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
//每次减一
countDownLatch.countDown();
System.out.println("1子线程开始执行任务结束");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是子线程2开始执行任务");
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
countDownLatch.countDown();
System.out.println("2子线程开始执行任务结束");
}
}).start();
countDownLatch.await();//如果>0就不执行下面,就会一直在等待,
直到<=0才往下执行
System.out.println("主线程开始执行任务");
for(int i = 0; i < 10; i++) {
System.out.println("main:i"+i);
}
}
}
程序演示结果
6、CyclicBarrier 也是让程序执行完毕再执行需要执行的代码,也是类似计数的功能
CyclicBarrier:CyclicBarrier初始化时规定一个数目, 然后计算调用了
CyclicBarrier.await()进入等待的线程数。
当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。
代码演示
package com.leeue.cn;
import java.util.concurrent.CyclicBarrier;
/**
*
* @classDesc: 功能描述:(
* CyclicBarrier初始化时规定一个数目,
* 然后计算调用了CyclicBarrier.await()进入等待的线程数。
* 当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。)
*
* 当五个线程执行写入数据完毕过后,再一起执行写入数据成功的语句
* @author:<a href="[email protected]">李月</a>
* @Version:v1.0
* @createTime:2018年7月23日 下午1:49:48
*/
class Writer extends Thread{
private CyclicBarrier cyclicBarrier;
public Writer(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"开始写入数据----");
Thread.sleep(30);
System.out.println(Thread.currentThread().getName()+"写入数据成功----");
cyclicBarrier.await();
//并行执行成功
System.out.println(Thread.currentThread().getName()+"所有数据执行完毕----");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 0; i < 5; i++) {
new Writer(cyclicBarrier).start();
}
}
}
执行效果图:
7、Semaphore 信号量的使用
Semaphore:是一种基于计数的信号量。它可以设定一个阈值,基于此,
线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,
我们也可以创建计数为1的Semaphore,
将其作为一种类似互斥锁的机制,
这也叫二元信号量,表示两种互斥状态。它的用法如下:
availablePermits函数用来获取当前可用的资源数量
其中使用的方法有:
// 最多支持多个资源的访问
Semaphore semaphore = new Semaphore(5);
// 表示获取到资源权限
semaphore.acquire();
// 获取到资源后减去1
semaphore.availablePermits();
// 释放资源
semaphore.release();
案例:
需求: 一个厕所只有3个坑位,但是有10个人来上厕所,那怎么办?假设10的人的编号分别为1-10,并且1号先到厕所,10号最后到厕所。那么1-3号来的时候必然有可用坑位,顺利如厕,4号来的时候需要看看前面3人是否有人出来了,如果有人出来,进去,否则等待。同样的道理,4-10号也需要等待正在上厕所的人出来后才能进去,并且谁先进去这得看等待的人是否有素质,是否能遵守先来先上的规则。
代码
package com.leeue.cn;
import java.util.Random;
import java.util.concurrent.Semaphore;
/**
*
* @classDesc: 功能描述:(Semaphore 信号量 也是类似计数的功能 )
* @author:<a href="[email protected]">李月</a>
* @Version:v1.0
* @createTime:2018年7月23日 下午2:07:39
*/
class Parent implements Runnable {
Semaphore wc;
String name;
public Parent(Semaphore wc, String name) {
this.wc = wc;
this.name = name;
}
@Override
public void run() {
try {
// 获取到资源 减1
int availablePermits = wc.availablePermits();
//System.out.println(availablePermits);
if (availablePermits > 0) {
System.out.println(name+"天助我也!我有茅坑了!");
} else {
System.out.println(name+"怎么没有茅坑了!");
}
//表示获取到了茅坑资源
wc.acquire();
System.out.println(name+"我终于能上厕所了!");
//模拟上厕所用的时间
Thread.sleep(new Random().nextInt(1000));
System.out.println(name+"厕所终于上完了");
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放资源
wc.release();
}
}
}
public class SemaphoreDemo {
/* 基本用法
// 最多支持多个资源的访问
Semaphore semaphore = new Semaphore(5);
// 表示获取到资源权限
semaphore.acquire();
// 获取到资源后减去1
semaphore.availablePermits();
// 释放资源
semaphore.release();
*/
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(3);
for(int i = 1; i <= 10; i++) {
new Thread(new Parent(semaphore, "我是第"+i+"人")).start();
}
}
}
8、并发队列ConcurrentLinkedDeque
分析:
并发队列
有界队列:
无界队列:
在并发队列中有界、无界区别在于一个支持有限制,一个无限制
所有的队列都是实现接口:Deque
无界安全队列:ConcurrentLinkedDeque
使用方法:
package com.leeue.cn;
import java.util.concurrent.ConcurrentLinkedDeque;
/**
* 无界安全队列
* @classDesc: 功能描述:(并发队列 ConcurrentLinkedDeque 队列是先进先出,后进后出原则)
* @author:<a href="[email protected]">李月</a>
* @Version:v1.0
* @createTime:2018年7月23日 下午3:15:24
*/
public class ConcurrentLinkedDequeDemo {
public static void main(String[] args) {
//无界队列 就是没有限制的队列 无限进入存储的队列
ConcurrentLinkedDeque concurrentLinkedDeque = new ConcurrentLinkedDeque();
concurrentLinkedDeque.offer("张三");//增加一个
concurrentLinkedDeque.offer("李四");
System.out.println(concurrentLinkedDeque.poll());// 取出一个长度会减一
System.out.println(concurrentLinkedDeque.peek());//取出一个,但是长度不会减一
System.out.println("长度"+concurrentLinkedDeque.size());
}
}
9、BlockingQueue阻塞队列
阻塞队列:当生产者写入满的时候,就会进入阻塞。
当队列为空的时候,消费者也会等待。
和非阻塞队列:
区别:
说明白这些: