JUC初识

JUC

1.ReentrantLock

    a)lock写在try之前
    b)一定要记得在finally里面进行unlock()

2.信号量

acquire():void ------>尝试获取锁,如果可以正常获取到,则执行后面的业务逻辑,如果获取失败,则阻塞等待
release():void------>释放锁

//信号量演示
public class ThreadMain98 {
    public static void main(String[] args) {
        //创建信号量
        Semaphore semaphore=new Semaphore(2,true);
        ThreadPoolExecutor executor=new ThreadPoolExecutor(10,10,
                0, TimeUnit.SECONDS,new LinkedBlockingQueue<>(100));

        for (int i = 0; i <4 ; i++) {
            //创建任务
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"到达停车场");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //试图进入停车场
                    try {
                        //尝试获取锁
                        semaphore.acquire();
                        //当代码只想到此处,说明已经获取到锁
                        System.out.println(Thread.currentThread().getName()+"进入停车场---------");
                        //车辆停留的时间
                        int num=1+new Random().nextInt(5);
                        try {
                            Thread.sleep(num*1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"离开停车场...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        //释放锁
                        semaphore.release();
                    }


                }
            });
        }

    }
}

3.计数器:CountDownLauth

计数器是用来保证一组线程同时完成某个操作之后,才能继续之后的任务。
await():void-----等待(当线程数量不满足CountDownLauth的数量的时候,会执行此代码会阻塞等待,直到数量满足之后,在执行await之后的代码。)
countDown():void

CountDownLauth是如何实现的?

答:CountDownLauth里面有一个计数器,计数器的数量在初始化的时候设置,每次调用countDown()方法的时候,计数器的数量-1,直到减到0之后,就可以执行await之后的代码。

import java.util.concurrent.CountDownLatch;

/**
 * 计数器
 */
public class ThreadMain99 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch=new CountDownLatch(5);
        for (int i = 1; i <6 ; i++) {
            int finaI=i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开始起跑");
                    try {
                        Thread.sleep(finaI*1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"到达终点");
                    //将计数器-1
                    latch.countDown();
                }
            }).start();
        }
        //阻塞等待
        latch.await();
        System.out.println("所有人都到达终点了,公布排名");
    }
}

在这里插入图片描述
声明计数器初始值为5
在这里插入图片描述
当计数器减到0之后,在执行await
在这里插入图片描述

CountDownLauth缺点

CountDownLauth计数器的使用是一次性的,当用完一次之后就不能使用了

4.循环屏障(循环栅栏):CyclicBarrier

await():int ------等待(CyclicBarrier里面有一个计数器,每次执行await方法的时候,计数器的数量-1,直到减到0之后,就可以执行await之后的代码,并且此时会将count值(计数器的值)重置继续利用。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * 循环屏障
 */
public class ThreadMain100 {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier=new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("执行了CyclicBarrier里面的Runnable");
            }
        });
        for (int i = 1; i < 11; i++) {
            int finalI=i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开始起跑");
                    try {
                        Thread.sleep(finalI*200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println(Thread.currentThread().getName()+"等待其他人-----------");
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    //代码执行到此行,说明已经有一组代码已经满足情况
                    System.out.println(Thread.currentThread().getName()+"执行结束");
                }
            }).start();

        }
    }
}

循环屏障的使用:

在这里插入图片描述
在这里插入图片描述
1.计数器-1
2.判断计数器是否为0,如果为0执行之后的代码,如果不为0阻塞等待
当计数器为0时,首先会执行await之后的代码,将计数器重置

CyclicBarrier和CountDownLatch区别?

答:CountDownLatch计数器只能使用一次,CyclicBarrier他的计数器可以重复使用。

HashMap

HashMap底层实现结构,负载因子,哈希冲突的解决等…线程问题
HashMap------非线程安全的容器
——JDK1.7死循环(要会画出来)
——JDK1.8数据覆盖

HashMap—>数组+链表 / 红黑树
HashMap 负载因子(加载因子)0.75 扩容:16*0.75=进行扩容
0.75:尽量的避免哈希冲突所带来的性能开销问题(空间换时间的方案)

HashMap线程安全方案

ConcurrentHashMap

JDK1.7是将ConcurrentHashMap分成几个segment进行加锁(分段锁)。
JDK1.8锁优化:读的时候不加锁,写的时候加锁,使用了大量的CAS,Voiltail…

Hashtable:线程安全的容器

在这里插入图片描述
给put方法直接加锁,因此一般情况不会使用Hashtable

HashMap,ConcurrentHashMap,Hashtable区别?

  1. HashMap是非线程安全的容器,他在JDK1.7造成死循环,JDK1.8会造成数据覆盖,Hashtable和ConcurrentHashMap都是线程安全的。
  2. Hashtable实现线程安全的手段比较简单,他是在给put方法整体加了一把锁,因此性能不高,所以使用频率比较低;而ConcurrentHashMap是Hash MAp在多线程下的替代方案,他在JDK1.7的时候使用的Lock加分段锁的方案来实现线程安全的保障,而在JDK1.8的时候使用了大量的使用了大量的CAS,Voiltail来实现线程的,并且在JDK1.8读取的时候不加锁(读取的数据可能不是最新,因为读取和写入同时进行),只有在写的时候才加锁。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值