vmware16虚拟机使用教程,JUC--02

代码很简单,就是将原来的元素复制到了一个新数组中,且长度应该加1,然后在新数组末尾加上要添加的元素,最后设置新数组为自己的array。

CopyOnWriteArrayList使用写时复制策略保证list的一致性,而获取–修改–写入三个步骤不是原子性,所以需要一个独占锁保证修改数据时只有一个线程能够进行。另外,CopyOnWriteArrayList提供了弱一致性的迭代器,从而保证在获取迭代器后,其他线程对list的修改是不可见的,迭代器遍历的数组是一个快照。

CopyOnWriteArrayList比Vector厉害在哪里?

Vector底层是使用synchronized关键字来实现的:效率特别低下。CopyOnWriteArrayList使用的是Lock锁,效率会更加高效!

CopyOnWriteArraySet

在这里插入图片描述

public class SetTest {

public static void main(String[] args) {

/**

    1. Set set = Collections.synchronizedSet(new HashSet<>());
    1. Set set = new CopyOnWriteArraySet<>();

*/

// Set set = new HashSet<>();

Set set = new CopyOnWriteArraySet<>();

for (int i = 1; i <= 30; i++) {

new Thread(() -> {

set.add(UUID.randomUUID().toString().substring(0,5));

System.out.println(set);

},String.valueOf(i)).start();

}

}

}

ConcurrentHashMap

public class MapTest {

public static void main(String[] args) {

//map 是这样用的吗? 不是,工作中不使用这个

//默认等价什么? new HashMap<>(16,0.75);

/**

  • 解决方案

    1. Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
  • Map<String, String> map = new ConcurrentHashMap<>();

*/

Map<String, String> map = new ConcurrentHashMap<>();

//加载因子、初始化容量

for (int i = 1; i < 100; i++) {

new Thread(()->{

map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));

System.out.println(map);

},String.valueOf(i)).start();

}

}

}

关于Callable

**1、可以有返回值;

2、可以抛出异常;

3、方法不同,run()/call()**

public class CallableTest {

public static void main(String[] args) throws ExecutionException, InterruptedException {

for (int i = 1; i < 10; i++) {

MyThread1 myThread1 = new MyThread1();

FutureTask futureTask = new FutureTask<>(myThread1);

// 放入Thread中使用,结果会被缓存

new Thread(futureTask,String.valueOf(i)).start();

// 这个get方法可能会被阻塞,如果在call方法中是一个耗时的方法,所以一般情况我们会把这个放在最后,或者使用异步通信

int a = futureTask.get();

System.out.println(“返回值:” + s);

}

}

}

class MyThread1 implements Callable {

@Override

public Integer call() throws Exception {

System.out.println(“call()”);

return 1024;

}

}

辅助并发类

1)CountDownLatch

public class CountDownLatchDemo {

public static void main(String[] args) throws InterruptedException {

// 总数是6

CountDownLatch countDownLatch = new CountDownLatch(6);

for (int i = 1; i <= 6; i++) {

new Thread(() -> {

System.out.println(Thread.currentThread().getName() + “==> Go Out”);

countDownLatch.countDown(); // 每个线程都数量 -1

},String.valueOf(i)).start();

}

countDownLatch.await(); // 等待计数器归零 然后向下执行

System.out.println(“close door”);

}

}

主要方法:

  • countDown 减一操作;

  • await 等待计数器归零

2)CyclickBarrier

集齐七颗龙珠召唤神龙

public class CyclicBarrierDemo {

public static void main(String[] args) {

// 主线程

CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() -> {

System.out.println(“召唤神龙”);

});

for (int i = 1; i <= 7; i++) {

// 子线程

int finalI = i;

new Thread(() -> {

System.out.println(Thread.currentThread().getName() + “收集了第” + finalI + “颗龙珠”);

try {

cyclicBarrier.await(); // 加法计数 等待

} catch (InterruptedException e) {

e.printStackTrace();

} catch (BrokenBarrierException e) {

e.printStackTrace();

}

},String.valueOf(finalI)).start();

}

}

}

3)Semaphore

public class SemaphoreDemo {

public static void main(String[] args) {

// 线程数量,停车位,限流

Semaphore semaphore = new Semaphore(3);

for (int i = 0; i <= 6; i++) {

new Thread(() -> {

// acquire() 得到

try {

semaphore.acquire();

System.out.println(Thread.currentThread().getName() + “抢到车位”);

TimeUnit.SECONDS.sleep(2);

System.out.println(Thread.currentThread().getName() + “离开车位”);

}catch (Exception e) {

e.printStackTrace();

}finally {

semaphore.release(); // release() 释放

}

}).start();

}

}

}

Thread-1抢到车位

Thread-0抢到车位

Thread-2抢到车位

Thread-0离开车位

Thread-2离开车位

Thread-1离开车位

Thread-5抢到车位

Thread-3抢到车位

Thread-4抢到车位

Thread-5离开车位

Thread-3离开车位

Thread-6抢到车位

Thread-4离开车位

Thread-6离开车位

Process finished with exit code 0

读写锁

未加读写锁

public class ReadWriteLockDemo {

public static void main(String[] args) {

MyCache myCache = new MyCache();

int num = 6;

for (int i = 1; i <= num; i++) {

int finalI = i;

new Thread(() -> {

myCache.write(String.valueOf(finalI), String.valueOf(finalI));

},String.valueOf(i)).start();

}

for (int i = 1; i <= num; i++) {

int finalI = i;

new Thread(() -> {

myCache.read(String.valueOf(finalI));

},String.valueOf(i)).start();

}

}

}

/**

  • 方法未加锁,导致写的时候被插队

*/

class MyCache {

private volatile Map<String, String> map = new HashMap<>();

public void write(String key, String value) {

System.out.println(Thread.currentThread().getName() + “线程开始写入”);

map.put(key, value);

System.out.println(Thread.currentThread().getName() + “线程写入ok”);

}

public void read(String key) {

System.out.println(Thread.currentThread().getName() + “线程开始读取”);

map.get(key);

System.out.println(Thread.currentThread().getName() + “线程写读取ok”);

}

}

2线程开始写入

2线程写入ok

3线程开始写入

3线程写入ok

1线程开始写入 # 插入了其他线程的写入,导致数据不一致

4线程开始写入

4线程写入ok

1线程写入ok

6线程开始写入

6线程写入ok

5线程开始写入

5线程写入ok

1线程开始读取

1线程写读取ok

2线程开始读取

2线程写读取ok

3线程开始读取

3线程写读取ok

4线程开始读取

4线程写读取ok

5线程开始读取

6线程开始读取

6线程写读取ok

5线程写读取ok

Process finished with exit code 0

加了读写锁

public class ReadWriteLockDemo {

public static void main(String[] args) {

MyCache2 myCache = new MyCache2();

int num = 6;

for (int i = 1; i <= num; i++) {

int finalI = i;

new Thread(() -> {

myCache.write(String.valueOf(finalI), String.valueOf(finalI));

},String.valueOf(i)).start();

}

for (int i = 1; i <= num; i++) {

int finalI = i;

new Thread(() -> {

myCache.read(String.valueOf(finalI));

},String.valueOf(i)).start();

}

}

}

class MyCache2 {

private volatile Map<String, String> map = new HashMap<>();

private ReadWriteLock lock = new ReentrantReadWriteLock();

public void write(String key, String value) {

lock.writeLock().lock(); // 写锁

try {

System.out.println(Thread.currentThread().getName() + “线程开始写入”);

map.put(key, value);

System.out.println(Thread.currentThread().getName() + “线程写入ok”);

}finally {

lock.writeLock().unlock(); // 释放写锁

}

}

public void read(String key) {

lock.readLock().lock(); // 读锁

try {

System.out.println(Thread.currentThread().getName() + “线程开始读取”);

map.get(key);

System.out.println(Thread.currentThread().getName() + “线程写读取ok”);

}finally {

lock.readLock().unlock(); // 释放读锁

}

}

}

1线程开始写入

1线程写入ok

6线程开始写入

6线程写入ok

3线程开始写入

3线程写入ok

2线程开始写入

2线程写入ok

5线程开始写入

5线程写入ok

4线程开始写入

4线程写入ok

1线程开始读取

5线程开始读取

2线程开始读取

1线程写读取ok

3线程开始读取

2线程写读取ok

6线程开始读取

6线程写读取ok

5线程写读取ok

4线程开始读取

4线程写读取ok

3线程写读取ok

Process finished with exit code 0

阻塞队列

在这里插入图片描述

1)BlockingQueue 有四组api

在这里插入图片描述

2)2)同步队列

package com.marchsoft.queue;

import java.util.concurrent.BlockingDeque;

import java.util.concurrent.BlockingQueue;

/**

  • Description:

  • @author jiaoqianjin

  • Date: 2020/8/12 10:02

**/

public class SynchronousQueue {

public static void main(String[] args) {

BlockingQueue synchronousQueue = new java.util.concurrent.SynchronousQueue<>();

// 网queue中添加元素

new Thread(() -> {

try {

System.out.println(Thread.currentThread().getName() + “put 01”);

synchronousQueue.put(“1”);

System.out.println(Thread.currentThread().getName() + “put 02”);

synchronousQueue.put(“2”);

System.out.println(Thread.currentThread().getName() + “put 03”);

synchronousQueue.put(“3”);

} catch (InterruptedException e) {

e.printStackTrace();

}

}).start();

// 取出元素

new Thread(()-> {

try {

System.out.println(Thread.currentThread().getName() + “take” + synchronousQueue.take());

System.out.println(Thread.currentThread().getName() + “take” + synchronousQueue.take());

System.out.println(Thread.currentThread().getName() + “take” + synchronousQueue.take());

}catch (InterruptedException e) {

e.printStackTrace();

}

}).start();

}

}

Thread-0put 01

Thread-1take1

Thread-0put 02

Thread-1take2

Thread-0put 03

Thread-1take3

Process finished with exit code 0

线程池

线程池:三大方式、七大参数、四种拒绝策略

池化技术:

池化技术:把一些能够复用的东西(比如说数据库连接、线程)放到池中,避免重复创建、销毁的开销,从而极大提高性能。

在开发过程中我们会用到很多的连接池,像是数据库连接池、HTTP 连接池、Redis

连接池等等。而连接池的管理是连接池设计的核心,我就以数据库连接池为例,来说明一下连接池管理的关键点。

1)线程池:三大方法
  • ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程

  • ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小

  • ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的

//工具类 Executors 三大方法;

public class Demo01 {

public static void main(String[] args) {

ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程

ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小

ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的

//线程池用完必须要关闭线程池

try {

for (int i = 1; i <=100 ; i++) {

//通过线程池创建线程

threadPool.execute(()->{

System.out.println(Thread.currentThread().getName()+ " ok");

});

}

} catch (Exception e) {

e.printStackTrace();

} finally {

threadPool.shutdown();

}

}

}

2)七大参数

public ThreadPoolExecutor(int corePoolSize, //核心线程池大小

int maximumPoolSize, //最大的线程池大小

long keepAliveTime, //超时了没有人调用就会释放

TimeUnit unit, //超时单位

BlockingQueue workQueue, //阻塞队列

ThreadFactory threadFactory, //线程工厂 创建线程的 一般不用动

RejectedExecutionHandler handler //拒绝策略

) {

if (corePoolSize < 0 ||

maximumPoolSize <= 0 ||

maximumPoolSize < corePoolSize ||

keepAliveTime < 0)

throw new IllegalArgumentException();

if (workQueue == null || threadFactory == null || handler == null)

throw new NullPointerException();

this.corePoolSize = corePoolSize;

this.maximumPoolSize = maximumPoolSize;

this.workQueue = workQueue;

this.keepAliveTime = unit.toNanos(keepAliveTime);

this.threadFactory = threadFactory;

this.handler = handler;

}

在这里插入图片描述

阿里巴巴的Java操作手册中明确说明:对于Integer.MAX_VALUE初始值较大,所以一般情况我们要使用底层的ThreadPoolExecutor来创建线程池。

public class PollDemo {

public static void main(String[] args) {

// 获取cpu 的核数

int max = Runtime.getRuntime().availableProcessors();

ExecutorService service =new ThreadPoolExecutor(

2,

max,

3,

TimeUnit.SECONDS,

new LinkedBlockingDeque<>(3),

Executors.defaultThreadFactory(),

new ThreadPoolExecutor.AbortPolicy()

);

try {

for (int i = 1; i <= 10; i++) {

service.execute(() -> {

System.out.println(Thread.currentThread().getName() + “ok”);

});

}

}catch (Exception e) {

e.printStackTrace();

}

finally {

service.shutdown();

}

}

}

3)拒绝策略
  1. new ThreadPoolExecutor.AbortPolicy(): //该拒绝策略为:银行满了,还有人进来,不处理这个人的,并抛出异常

  2. new ThreadPoolExecutor.CallerRunsPolicy(): //该拒绝策略为:哪来的去哪里 main线程进行处理

  3. new ThreadPoolExecutor.DiscardPolicy(): //该拒绝策略为:队列满了,丢掉异常,不会抛出异常。

  4. new ThreadPoolExecutor.DiscardOldestPolicy(): //该拒绝策略为:队列满了,尝试去和最早的进程竞争,不会抛出异常

4)如何设置线程池的大小
  • CPU密集型:电脑的核数是几核就选择几;选择maximunPoolSize的大小

// 获取cpu 的核数

int max = Runtime.getRuntime().availableProcessors();

ExecutorService service =new ThreadPoolExecutor(

2,

max,

3,

TimeUnit.SECONDS,

new LinkedBlockingDeque<>(3),

Executors.defaultThreadFactory(),

new ThreadPoolExecutor.AbortPolicy()

);

  • I/O密集型:在程序中有15个大型任务,io十分占用资源;I/O密集型就是判断我们程序中十分耗I/O的线程数量,大约是最大I/O数的一倍到两倍之间。

四大函数式接口

lambda表达式、链式编程、函数式接口、Stream流式计算

函数式接口:只有一个方法的接口

1)Function 函数型接口

在这里插入图片描述

public class FunctionDemo {

public static void main(String[] args) {

Function<String, String> function = (str) -> {return str;};

System.out.println(function.apply(“aaaaaaaaaa”));

}

}

2)Predicate 断定型接口

在这里插入图片描述

public class PredicateDemo {

public static void main(String[] args) {

Predicate predicate = (str) -> {return str.isEmpty();};

// false

System.out.println(predicate.test(“aaa”));

// true

System.out.println(predicate.test(“”));

}

}

3)Suppier 供给型接口

在这里插入图片描述

/**

  • 供给型接口,只返回,不输入

*/

public class Demo4 {

public static void main(String[] args) {

Supplier supplier = ()->{return “1024”;};

System.out.println(supplier.get());

}

}

4)Consummer 消费型接口

在这里插入图片描述

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代成为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。

更多JVM面试整理:

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

4)Consummer 消费型接口

在这里插入图片描述

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-ze6XPaOL-1713436310645)]

[外链图片转存中…(img-PeDqAf1s-1713436310646)]

[外链图片转存中…(img-Gs4CYz4v-1713436310646)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代成为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。

[外链图片转存中…(img-gto47C7a-1713436310646)]

更多JVM面试整理:

[外链图片转存中…(img-x67r3fzU-1713436310647)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值