首页
关于
友链
Search
1
wlop 4K 壁纸 4k8k 动态 壁纸
1,509 阅读
2
Nacos持久化MySQL问题-解决方案
958 阅读
3
Docker搭建Typecho博客
762 阅读
4
滑动时间窗口算法
746 阅读
5
Nginx反向代理微服务配置
716 阅读
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
登录
Search
标签搜索
java
javase
docker
java8
springboot
thread
spring
分布式
mysql
锁
linux
redis
源码
typecho
centos
git
map
RabbitMQ
lambda
stream
少年
累计撰写
189
篇文章
累计收到
24
条评论
首页
栏目
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
页面
关于
友链
搜索到
30
篇与
的结果
2022-03-19
wait、notifyAll()、await()、signalAll()
wait、notifyAll()、await()、signalAll()为了避免虚假唤醒问题,应该总是使用在循环中wait、notifyAll():package com.yanxizhu; import java.util.function.Consumer; /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public static void main(String[] args) { Clerk clerk = new Clerk(); Productor pro = new Productor(clerk); Consumers cus = new Consumers(clerk); new Thread(pro, "生产者 A").start(); new Thread(cus, "消费者 B").start(); new Thread(pro, "生产者 C").start(); new Thread(cus, "消费者 D").start(); } } //店员 class Clerk{ private int product = 0; //进货 public synchronized void get(){//循环次数:0 while(product >= 1){//为了避免虚假唤醒问题,应该总是使用在循环中 System.out.println("产品已满!"); try { this.wait(); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName() + " : " + ++product); this.notifyAll(); } //卖货 public synchronized void sale(){//product = 0; 循环次数:0 while(product <= 0){ System.out.println("缺货!"); try { this.wait(); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName() + " : " + --product); this.notifyAll(); } } //生产者 class Productor implements Runnable{ private Clerk clerk; public Productor(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { } clerk.get(); } } } //消费者 class Consumers implements Runnable{ private Clerk clerk; public Consumers(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { clerk.sale(); } } }await()、signalAll()package com.yanxizhu; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * 生产者消费者案例: */ public class TestProductorAndConsumerForLock { public static void main(String[] args) { Clerk clerk = new Clerk(); Productor pro = new Productor(clerk); Consumer con = new Consumer(clerk); new Thread(pro, "生产者 A").start(); new Thread(con, "消费者 B").start(); // new Thread(pro, "生产者 C").start(); // new Thread(con, "消费者 D").start(); } } class Clerk { private int product = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); // 进货 public void get() { lock.lock(); try { if (product >= 1) { // 为了避免虚假唤醒,应该总是使用在循环中。 System.out.println("产品已满!"); try { condition.await(); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName() + " : " + ++product); condition.signalAll(); } finally { lock.unlock(); } } // 卖货 public void sale() { lock.lock(); try { if (product <= 0) { System.out.println("缺货!"); try { condition.await(); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName() + " : " + --product); condition.signalAll(); } finally { lock.unlock(); } } } // 生产者 class Productor implements Runnable { private Clerk clerk; public Productor(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.get(); } } } // 消费者 class Consumer implements Runnable { private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { clerk.sale(); } } }
2022年03月19日
195 阅读
0 评论
5 点赞
2022-03-19
ReentrantLock显示锁
package com.yanxizhu; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @description: ReentrantLock * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/19 12:37 * @version: 1.0 */ public class LockDemo { public static void main(String[] args) { titck titck = new titck(); new Thread(titck,"线程1").start(); new Thread(titck,"线程2").start(); new Thread(titck,"线程3").start(); } public static class titck implements Runnable{ Lock lock = new ReentrantLock(); private int titck = 100; @Override public void run() { while(true){ lock.lock(); try{ if(titck>0){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("剩余票数:"+--titck); } }finally { lock.unlock(); } } } } } synchronized:隐式锁1、同步代码块2、同步方法jdk1.5之后:显示锁3、同步锁Lock注意:是一个显示锁,需要通过lock()方法上锁,必须通过unlock()方法进行释放锁。
2022年03月19日
140 阅读
0 评论
3 点赞
2022-03-19
FutureTask用于闭锁
package com.yanxizhu; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @description: FutureTask可用于闭锁 * @date: 2022/3/19 11:48 * @version: 1.0 */ public class FutureTaskDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { myFutureTask myFutureTask = new myFutureTask(); FutureTask<Integer> futureTask = new FutureTask<>(myFutureTask); new Thread(futureTask).start(); //必须等线程执行完,才执行下面的代码,因此FutureTask可用于闭锁 Integer integer = futureTask.get(); System.out.println("integer="+integer); System.out.println("======================="); } public static class myFutureTask implements Callable<Integer>{ @Override public Integer call() throws Exception { int i=1; for(;i<1000000;i++){ i++; } return i; } } }
2022年03月19日
161 阅读
0 评论
5 点赞
2022-03-19
CopyOnWriteArrayList遍历集合
package com.yanxizhu; import java.util.*; /** * @description: synchronizedList遍历错误 * @date: 2022/3/19 11:30 * @version: 1.0 */ public class ConCurrentHashMapTest { public static void main(String[] args) { conCurrentDemo conCurrentDemo = new conCurrentDemo(); for(int i=0;i<5;i++){ new Thread(conCurrentDemo).start(); } } public static class conCurrentDemo implements Runnable{ //并发线程安全,修改报错 private static List<String> list = Collections.synchronizedList(new ArrayList<>()); static { list.add("apple"); list.add("xiaomi"); list.add("huawei"); } @Override public void run() { Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); list.add("iphone"); } } } }线程安全报错:Exception in thread "Thread-0" Exception in thread "Thread-3" Exception in thread "Thread-4" Exception in thread "Thread-2" Exception in thread "Thread-1" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1043) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:997) at com.yanxizhu.ConCurrentHashMapTest$conCurrentDemo.run(ConCurrentHashMapTest.java:35) at java.base/java.lang.Thread.run(Thread.java:834) java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1043) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:997) at com.yanxizhu.ConCurrentHashMapTest$conCurrentDemo.run(ConCurrentHashMapTest.java:35) at java.base/java.lang.Thread.run(Thread.java:834)通过用CopyOnWriteArrayList修改:package com.yanxizhu; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** * @description: CopyOnWriteArrayList遍历集合 * @date: 2022/3/19 11:30 * @version: 1.0 */ public class ConCurrentHashMapTest { public static void main(String[] args) { conCurrentDemo conCurrentDemo = new conCurrentDemo(); for(int i=0;i<5;i++){ new Thread(conCurrentDemo).start(); } } public static class conCurrentDemo implements Runnable{ //并发线程安全,修改报错 // private static List<String> list = Collections.synchronizedList(new ArrayList<>()); private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); static { list.add("apple"); list.add("xiaomi"); list.add("huawei"); } @Override public void run() { Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); //CopyOnWriteArrayList,每次会重新复制一个新的,添加。 list.add("iphone"); } } } }
2022年03月19日
217 阅读
0 评论
2 点赞
2022-03-19
Atomic原子类的使用
import java.util.concurrent.atomic.AtomicInteger; /** * @description: Atomic使用 * @date: 2022/3/19 10:14 * @version: 1.0 */ public class AtomicDemo { public static void main(String[] args) { ////通过synchronized、volatile实现 // demo demo = new demo(); // for(int i=0;i<10;i++){ // new Thread(demo).start(); // } //使用AtomicInteger实现 demo2 demo = new demo2(); for(int i=0;i<10;i++){ new Thread(demo).start(); } } //通过synchronized、volatile实现 public static class demo implements Runnable{ private volatile int num=0; @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num="+getNums()); } public synchronized int getNums(){ return num ++; } } //使用AtomicInteger实现 public static class demo2 implements Runnable{ AtomicInteger num = new AtomicInteger(); @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("num="+getNums()); } public int getNums(){ return num.getAndIncrement(); } } }
2022年03月19日
157 阅读
0 评论
6 点赞
2022-03-19
CountDownLatch闭锁使用
import java.util.concurrent.CountDownLatch; /** * @date: 2022/3/19 11:09 * @version: 1.0 */ public class CountDownLatchTest { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(5); myCountDownlatch myCountDownlatch = new myCountDownlatch(countDownLatch); long start = System.currentTimeMillis(); for(int i=0;i<5;i++){ new Thread(myCountDownlatch).start(); } countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); } public static class myCountDownlatch implements Runnable{ private CountDownLatch countDownLatch; public myCountDownlatch(CountDownLatch countDownLatch){ this.countDownLatch = countDownLatch; } @Override public void run() { synchronized (this){ try{ for(int i =0;i<500;i++){ if(i % 2==0){ System.out.println(i); } } }finally { countDownLatch.countDown(); } } } } }
2022年03月19日
190 阅读
0 评论
5 点赞
2022-03-11
CompletableFuture异步编排
通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。因此我们可以使用completableFuture 异步编排方案。比如:一个业务场景,需要同时获取多个数据,如果同步线程挨个执行,则需要时间为所有线程执行时间的总和。如果我们使用异步线程执行,所需时间则为耗时最长那个异步线程的执行时间。如果多个异常线程之间还存在依赖关系,比如线程3需要线程1的执行结果,线程6依赖线程3、线程2,那这个问题怎么解决呢。那就可以使用completableFuture 异步编排方案实现。注意:completableFuture 是jdk1.8之后添加的一个功能。CompletableFuture接口:public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {public interface Future<V> {以前用到的FutureTask就是用到的Future可以得到返回结果public class FutureTask<V> implements RunnableFuture<V> {public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }Future可以得到返回结果CompletableFuture随便一个方法,都接受一个Function public <U> CompletableFuture<U> applyToEither( CompletionStage<? extends T> other, Function<? super T, U> fn) { return orApplyStage(null, other, fn); }@FunctionalInterface public interface Function<T, R> {Function是一个@FunctionalInterface,所以对Lambda使用要熟悉。CompletableFuture异步编排问题多个异步线程远程调用会导致丢失请求头,原因是多个线程,通过拦截器不能获取其它线程的请求的heard信息。解决方案:每个线程共享自己的requestAttributes。自定义feign拦截器:import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /** * @description: TODO * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 23:03 * @version: 1.0 */ @Configuration public class FamilyFegin { @Bean(name ="requestInterceptor") public RequestInterceptor requestInterceptor(){ return new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { //RequestContextHolder拿到刚请求来的数据 ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); System.out.println("requestAttributes线程"+Thread.currentThread().getId()); HttpServletRequest request = requestAttributes.getRequest(); System.out.println("调用feign之前"); if(request != null){ //同步请求头数据 String cookie = request.getHeader("Cookie");//老数据 //给新请求同步老请求的cookie requestTemplate.header("Cookie", cookie); } } }; } }web配置:因为需要拦截器生效import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @description: WEB配置 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 22:40 * @version: 1.0 */ public class FamilyWebConfig implements WebMvcConfigurer { @Autowired LoginUserInterceptor loginUserInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginUserInterceptor).addPathPatterns("/**"); } }CompletableFuture异步编排import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @description: CompletableFuture异步编排 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 23:32 * @version: 1.0 */ public class MyCompletableFuture { public static ExecutorService executorService = Executors.newFixedThreadPool(10); public void myOpenFeign() throws ExecutionException, InterruptedException { System.out.println("主线程0"); //远程调用存在丢失请求头的问题,因为不在同一线程,导致自定义拦截器不能获取head信息。 //解决丢失请求头方案: ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); //第一个异步任务 CompletableFuture<Void> oneFuture = CompletableFuture.runAsync(() -> { System.out.println("辅线程1"); //每个线程都共享一下自己的requestAttributes RequestContextHolder.setRequestAttributes(requestAttributes); //异步线程远程调用,业务1 //异步线程调用业务代码 }, executorService); //第二个异步任务 CompletableFuture<Void> twoFuture = CompletableFuture.runAsync(() -> { System.out.println("辅线程2"); //每个线程都共享一下自己的requestAttributes RequestContextHolder.setRequestAttributes(requestAttributes); //异步线程远程调用,业务2 //异步线程调用业务代码 }, executorService); CompletableFuture.allOf(oneFuture, twoFuture).get(); } }以上就是解决CompletableFuture异步编排,异步多线程引起的远程调用请求丢失解决方案。代码中共享requestAttributes原因ThreadLocal数据:ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();RequestContextHolder主线程不一样获取的数据不一样,如下:import javax.faces.context.FacesContext; import org.springframework.core.NamedInheritableThreadLocal; import org.springframework.core.NamedThreadLocal; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; public abstract class RequestContextHolder { private static final boolean jsfPresent = ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader()); private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes"); private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context"); public RequestContextHolder() { }
2022年03月11日
415 阅读
0 评论
5 点赞
2022-03-10
JAVA多线程4种实现方式
异步与线程池1、初始化线程的4种方式1)、继承Thread2)、实现Runnable接口3)、实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)4)、线程池方式1和方式2:主进程无法获取线程的运算结果。不适合当前场景。方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致服务器资源耗尽。方式4:通过如下两种方式初始化线程池Executors.newFiexed ThreadPool(3); //或者 new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit unit, workQueue,threadFactory,handler);方式1、继续Thread/** * @description: 继承Thread * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 21:06 * @version: 1.0 */ public class MyThread { public static void main(String[] args) { System.out.println("启动main方法开始"); OneMyThread oneMyThread = new OneMyThread(); oneMyThread.start(); System.out.println("结束main方法"); } public static class OneMyThread extends Thread{ @Override public void run() { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("运行结果:"+i); } } }运行结果:启动main方法开始 结束main方法 当前线程:22 运行结果:5方式2、实现Runable接口/** * @description: 实现Runnable接口 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 21:06 * @version: 1.0 */ public class MyThread { public static void main(String[] args) { System.out.println("启动main方法开始"); TwoMyThread twoMyThread = new TwoMyThread(); new Thread(twoMyThread).start(); System.out.println("结束main方法"); } /** * 实现Runnable接口 */ public static class TwoMyThread implements Runnable { @Override public void run() { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("运行结果:"+i); } } }运行结果:启动main方法开始 结束main方法 当前线程:22 运行结果:5方式3、实现Callable泛型接口/** * @description: 继承Thread * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 21:06 * @version: 1.0 */ public class MyThread { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("启动main方法开始"); FutureTask<Integer> futureTask = new FutureTask<>(new ThreeMyThread()); new Thread(futureTask).start(); //等待线程执行完成,返回结果 Integer i = futureTask.get(); System.out.println("线程执行完,返回结果:"+i); System.out.println("结束main方法"); } /** * 实现Callable<T>泛型接口 */ public static class ThreeMyThread implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("运行结果:"+i); return i; } } }运行结果:启动main方法开始 当前线程:22 运行结果:5 线程执行完,返回结果:5 结束main方法注意:结果的顺序,可以看到是一个阻塞等待通过FutureTask类源码可以看到,FutureTask不仅可以接受Callable还可以接收Runnable.FutureTask源码如下:public class FutureTask<V> implements RunnableFuture<V> { /** * Creates a {@code FutureTask} that will, upon running, execute the * given {@code Runnable}, and arrange that {@code get} will return the * given result on successful completion. * * @param runnable the runnable task * @param result the result to return on successful completion. If * you don't need a particular result, consider using * constructions of the form: * {@code Future<?> f = new FutureTask<Void>(runnable, null)} * @throws NullPointerException if the runnable is null */ public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }FutureTask实现RunnableFuture接口:RunnableFuture最终是继承的Runnable。package java.util.concurrent; /** * A {@link Future} that is {@link Runnable}. Successful execution of * the {@code run} method causes completion of the {@code Future} * and allows access to its results. * @see FutureTask * @see Executor * @since 1.6 * @author Doug Lea * @param <V> The result type returned by this Future's {@code get} method */ public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }方式4、直接提交线程池,线程池会自动开启任务。每次通过new Thread()创建线程问题:导致资源耗尽。以上三种启动方式都不用。应该将所有异步多线程任务交给线程池执行。线程池:package com.yanxizhu.family.booking; import java.util.concurrent.*; /** * @description: 继承Thread * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/3/10 21:06 * @version: 1.0 */ public class MyThread { //应保证,当前系统中线程池只有一两个,每个异步任务,提交给线程池自己执行。 public static ExecutorService executorService = Executors.newFixedThreadPool(10); public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("启动main方法开始"); executorService.submit(new TwoMyThread()); //有返回值 //每个异步任务,提交给线程池自己执行。 executorService.execute(new TwoMyThread());//无返回值 System.out.println("结束main方法"); } /** * 实现Runnable接口 */ public static class TwoMyThread implements Runnable { @Override public void run() { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("运行结果:"+i); } } } 运行结果:启动main方法开始 结束main方法 当前线程:22 运行结果:5使用线程池带来的好处:1、降低资源的消耗通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗2、提高响应速度因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行3、提高线程的可管理性线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配总结区别1、直接继承Thread、实现Runnable接口:不能直接得到返回值。2、实现Callable泛型接口:可以得到返回值。3、继承Thread、实现Runnable接口、实现Callable泛型接口,都不能达到控制资源的效果。4、只有线程池可以控制资源,性能稳定。
2022年03月10日
173 阅读
0 评论
1 点赞
2022-03-08
高并发中集合问题
第一代线程安全集合类Vector、Hashtable是怎么保证线程安排的:使用synchronized修饰方法缺点:效率低下第二代线程非安全集合类ArrayList、HashMap线程不安全,但是性能好,用来替代Vector、Hashtable使用ArrayList、HashMap,需要线程安全怎么办呢?使用Collections.synchronizedList(list);Collections.synchronizedMap(m);底层使用synchronized代码块锁虽然也是锁住了所有的代码,但是锁在方法里边,并所在方法外边性能可以理解为稍有提高吧。毕竟进方法本身就要分配资源的第三代线程安全集合类在大量并发情况下如何提高集合的效率和安全呢?java.util.concurrent.*ConcurrentHashMap:CopyOnWriteArrayList:CopyOnWriteArraySet:注意不是CopyOnWriteHashSet*底层大都采用Lock锁(1.8的ConcurrentHashMap不使用Lock锁),保证安全的同时,性能也很高。
2022年03月08日
154 阅读
0 评论
2 点赞
1
2
3
4