Java架构学习(四)Vector与ArrayList区别&HashTable与HashMap源码分析&ConcurrentHashMap(分段)&CountDownLatch(类似计数的)&Cycl

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阻塞队列

阻塞队列:当生产者写入满的时候,就会进入阻塞。
        当队列为空的时候,消费者也会等待。
和非阻塞队列:
区别:

说明白这些:

这里写图片描述

10、使用BlockQueue模拟生产者与消费者

猜你喜欢

转载自blog.csdn.net/leeue/article/details/81008704
今日推荐