常用集合
集合
Java 集合框架提供了一套性能优良,使用方便的接口和类,java集合框架位于java.util包中,现分为Collection、Map、Queue三大类。
常用Collection
ArrayList
简介
在多线程环境下,由于线程不安全,会出现各种异常,用于单线程。
代码
public void listDemo(){
for (int i = 0; i < 30; i++) {
new Thread(()->{
while (list.size()>0){
System.out.println("卖出: "+list.remove(0)+" 的票");
}
}).start();
}
}
Vector
简介
在多线程环境下,由于自带synchronized属性,故是线程安全的,不会发生任何异常。
代码
public void vectorDemo(){
for (int i = 0; i < 30; i++) {
new Thread(()->{
while (tickets.size()>0){
//这不加锁的原因,①:remove方法是线程安全的 ②:在真正remove之前,会在remove方法里面再次判断size长度
System.out.println("卖出: "+tickets.remove(0)+" 的票");
}
}).start();
}
}
常用Collection
HashMap
简介
HashMap在多线程下,是不安全的,但是运用Collections.synchronizedMap后,线程是安全的,效率和HashTable一样,较差。
代码
public static class Constants {
public static final int COUNT = 10000;
public static final int THREAD_COUNT = 10;
}
static HashMap<UUID, UUID> m = new HashMap<>();
static Map<UUID, UUID> mSyn = Collections.synchronizedMap(new HashMap<UUID, UUID>());
static ConcurrentHashMap<UUID, UUID> mCurr = new ConcurrentHashMap();
static int count = Constants.COUNT;
static UUID[] keys = new UUID[count];
static UUID[] values = new UUID[count];
static final int THREAD_COUNT = Constants.THREAD_COUNT;
static {
for (int i = 0; i < count; i++) {
keys[i] = UUID.randomUUID();
values[i] = UUID.randomUUID();
}
}
static class MyThread extends Thread {
int start;
int gap = count/THREAD_COUNT;
public MyThread(int start) {
this.start = start;
}
@Override
public void run() {
for(int i=start; i<start+gap; i++) {
mSyn.put(keys[i], values[i]);
}
}
}
static class MyThreadCurr extends Thread {
int start;
int gap = count/THREAD_COUNT;
public MyThreadCurr(int start) {
this.start = start;
}
@Override
public void run() {
for(int i=start; i<start+gap; i++) {
mCurr.put(keys[i], values[i]);
}
}
}
public void hashMapDemo() {
long start = System.currentTimeMillis();
Thread[] threads = new Thread[THREAD_COUNT];
for(int i=0; i<threads.length; i++) {
threads[i] =new MyThread(i * (count/THREAD_COUNT));
}
for(Thread t : threads) {
t.start();
}
for(Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
// HashMap 2 添加Collections.synchronizedMap后 4
System.out.println(end - start);
// HashMap 6281 添加Collections.synchronizedMap后 10000
System.out.println(mSyn.size());
}
ConcurrentHashMap
简介
多线程时一般使用,插入数据时比HashTable慢,但是读时比HashTable快.
代码
public void concurrentHashMapDemo(){
long start = System.currentTimeMillis();
Thread[] threads = new Thread[THREAD_COUNT];
for(int i=0; i<threads.length; i++) {
threads[i] =new MyThreadCurr(i * (count/THREAD_COUNT));
}
for(Thread t : threads) {
t.start();
}
for(Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
// 3
System.out.println(end - start);
// 10000
System.out.println(mCurr.size());
}
ConcurrentSkipListMap
简介
线程安全: 并且自动排序.
代码
public void ConcurrentSkipDemo() {
//高并发并且排序
ConcurrentSkipListMap<String, String> skipMap = new ConcurrentSkipListMap<>();
Random r = new Random();
Thread[] ths = new Thread[10];
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++) {
skipMap.put("a"+Thread.currentThread().getName() + j, "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);
System.out.println(skipMap.size());
}
常用Queue
Queue队列常用案例: 线程池中。
ConcurrentLinkedDeque
简介
ConcurrentLinkedDeque 是最新的一个接口,主要就是为了多线程使用。方法里面并没有并没有加锁,效率较高。
代码
public void currQueueDemo() {
ConcurrentLinkedDeque<String> tickets = new ConcurrentLinkedDeque<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
while (true) {
String s = tickets.poll();
if (s == null) {
break;
} else {
System.out.println("销售了--" + s);
}
}
}).start();
}
}
LinkedBlockingQueue
简介
LinkedBlockingQueue则和LinkedList一样,内部基于链表来存放元素,线程安全。
代码
public void blockQueueDemo() {
//容器默认最大值为Integer.MAX_VALUE
LinkedBlockingQueue<String> strs = new LinkedBlockingQueue();
Random r = new Random();
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 void arrayBlockingQueueDemo() throws InterruptedException {
BlockingQueue<String> strs = new ArrayBlockingQueue<>(10);
for (int i = 0; i < 10; i++) {
strs.put("a" + i);
}
//满了就会等待,程序阻塞
// strs.put("aaa");
//满了之后他会报异常
// strs.add("aaa");
//offer用返回值来判断到底加没加成功
strs.offer("aaa");
//1秒钟之后如果加不进去它就返回到底加没加成功
strs.offer("aaa", 1, TimeUnit.SECONDS);
System.out.println(strs);
}
DelayQueue
简介
DelayQueue可以实现一个优先级排序的队列,具体实现方式为compareTo.
代码
public void delayQueueDemo() throws InterruptedException {
DelayQueue<MyTask> tasks = new DelayQueue<MyTask>();
long now = System.currentTimeMillis();
MyTask t1 = new MyTask("t1", now + 100000);
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++) {
//take()是阻塞的,一定要等getDelay()方法返回0时,才能取出其数据
System.out.println(tasks.take());
}
}
public static class MyTask implements Delayed {
String name;
long time;
public MyTask(String name, long time) {
this.name = name;
this.time = time;
}
/**
* 元素进入队列后,先进行排序,然后,只有getDelay也就是剩余时间为0的时候,
* 该元素才有资格被消费者从队列中取出来,所以构造函数一般都有一个时间传入。
**/
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
/**
* compareTo 方法必须提供与 getDelay 方法一致的排序,也就是说compareTo方法里可以按照
* getDelay方法的返回值大小排序,即在compareTo方法里比较getDelay方法返回值大小
**/
@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 String toString() {
return name + " " + time;
}
}
SynchronousQueue
简介
SynchronousQueue容量为0,就是这个东西它不是用来装内容的.
代码
public void synchronusQueueDemo() throws InterruptedException {
BlockingQueue<String> strs = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.MILLISECONDS.sleep(100);
//阻塞等待消费者消费,没有消费者进行阻塞
// strs.put("aaa");
//没有消费者等待,你则不能往其容器中添加元素
strs.add("aaa");
System.out.println(strs.size());
}
LinkedTransferQueue
简介
它可以给线程来传递任务,以此同时不像是SynchronousQueue只能传递一个,TransferQueue做成列表可以传好多个。
代码
public void LinkedTransferQueueDemo() throws InterruptedException {
LinkedTransferQueue<String> strs = new LinkedTransferQueue<>();
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
System.out.println(strs.take());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
//装完在这等着,阻塞等有人把它取走我这个线程才回去干我自己的事情。
// strs.transfer("aaa");
for (int i = 0; i < 100; i++) {
strs.put("aaa"+i);
}
}
Gitee地址
XFS