建设部继续教育网站,统一企业信息管理系统网站,wordpress 排序,青海省网站建设平台目录 一、降低锁的粒度#xff0c;将synchronized关键字不放在方法上了#xff0c;改为synchronized代码块。二、先区分一下公平锁和非公平锁1、公平锁2、非公平锁3、公平锁的优缺点#xff1a;4、非公平锁的优缺点#xff1a; 三、是否对症下药四、IntStream.rangeClosed是… 目录 一、降低锁的粒度将synchronized关键字不放在方法上了改为synchronized代码块。二、先区分一下公平锁和非公平锁1、公平锁2、非公平锁3、公平锁的优缺点4、非公平锁的优缺点 三、是否对症下药四、IntStream.rangeClosed是干嘛的五、parallel是干嘛的1、parallel()是什么2、举一个简单的demo3、parallel()的优缺点4、何时使用parallel() 大家好我是哪吒。
上一章提到了i的线程安全问题最终方案是在两个方法上添加synchronized关键字从而避免i的线程安全问题不过这样真的好吗在所有有线程安全的方法都添加synchronized
答案是显而易见的不行。
synchronized会极大的降低程序的性能导致整个程序几乎只能支持单线程操作性能显著降低。
那么如何解决呢
一、降低锁的粒度将synchronized关键字不放在方法上了改为synchronized代码块。
锁的粒度更小了也解决了这个问题确实可以的。
package com.guor.thread;public class SynchronizedTest2 {int a 1;int b 1;public void add() {System.out.println(add start);synchronized (this) {for (int i 0; i 10000; i) {a;b;}}System.out.println(add end);}public synchronized void compare() {System.out.println(compare start);synchronized (this) {for (int i 0; i 10000; i) {boolean flag a b;if (flag) {System.out.println(a a ,b b flag flag ,a b (a b));}}}System.out.println(compare end);}public static void main(String[] args) {SynchronizedTest2 synchronizedTest new SynchronizedTest2();new Thread(() - synchronizedTest.add()).start();new Thread(() - synchronizedTest.compare()).start();}
}为了更好的优化有的时候可以将synchronized代码块变为区分读写场景的读写锁也可以考虑悲观锁和乐观锁的区分。
对于读写场景比较多的情况可以使用ReentrantReadWriteLock区分读写再次降低锁的粒度提高程序的性能。
ReentrantReadWriteLock 还可以选择提供了公平锁在没有明确必须使用公平锁的情况下尽量不要使用公平锁公平锁会使程序性能降低很多很多。
二、先区分一下公平锁和非公平锁
公平锁多个线程按照申请锁的顺序去获得锁线程会直接进入队列去排队永远都是队列的第一个得到锁。非公平锁多个线程去获取锁的时候会直接去尝试获取获取不到进入等待队列如果能获取到就直接获取到锁。
简单来说公平锁谁先排队谁先执行非公平锁不用排队每个人都有机会。
1、公平锁
有一天早上云韵、美杜莎、小医仙结伴去买酱香拿铁到了咖啡店先排队一个一个来。不一会哪吒来了也买酱香拿铁只能在末尾排队。这个就是公平锁。 2、非公平锁
但是呢第二天早上哪吒又去买酱香拿铁上一次去晚了没买到线程被饿死了这次急了要插队买不讲武德。终于喝上了心心念念的酱香拿铁这个就是非公平锁。 3、公平锁的优缺点
优点所有线程都会获取到锁只是一个时间的问题不会出现有线程被饿死的情况缺点吞吐量会下降很多队列里只有第一个线程能获取到锁其他的线程都会阻塞cpu唤醒阻塞线程的开销会增大。
4、非公平锁的优缺点
优点可以减少CPU唤醒线程的开销整体的吞吐效率会高点CPU也不必取唤醒所有线程会减少唤起线程的数量。缺点如果运气不好会出现一致获取不到锁的情况会被活活的饿死。
三、是否对症下药
我们都知道静态字段属于类类级别的锁才能保护非静态字段属于类实例实例级别的锁才能保护。
先看一下下面的代码
import lombok.Data;import java.util.stream.IntStream;Data
public class LockTest {public static void main(String[] args) {IntStream.rangeClosed(1, 100000).parallel().forEach(i - new LockTest().increase());System.out.println(time);}private static int time 0;public synchronized void increase() {time;}
}在LockTest类中定义一个静态变量time定义一个非静态方法increase()实现time自增。先累加10万次测试一下。看看是否有线程安全的问题。 这…不对啊上一节在介绍高并发下i线程安全问题的时候synchronized 是好使的啊。
今天这是怎么了再运行一次结果依然如此不等于100000
先来分析一下。
在非静态的方法上加synchronized只能确保多个线程无法执行同一个实例的increase()方法却不能保证不同实例的increase()方法。 静态的变量time在多个线程中共享所以会出现线程安全的问题synchronized失效了。
那么将synchronized改为静态方法是不是就可以了试一下。
有两种写法一种是直接将方法改为静态方法一种是使用synchronized代码块。
private static Object obj new Object();
public void increase() {synchronized (obj) {time;}
}四、IntStream.rangeClosed是干嘛的
很多小伙伴可能会好奇这个是干什么的干了5年后端代码开发了没见过这玩意儿。
IntStream是一种特殊的stream用来提供对int相关的stream操作。
IntStream.rangeClosed生成某个数字范围内的数字集合的stream。
比如上面代码中的IntStream.rangeClosed(1, 100000).parallel().forEach(i - new LockTest().increase());。
range不包含10000rangeClosed包含10000
关于Java8 新特性 Stream流的详细介绍可以看一下这个【Java8 新特性 5】Java 8 stream的详细用法。
五、parallel是干嘛的
1、parallel()是什么
Stream.parallel() 方法是 Java 8 中 Stream API 提供的一种并行处理方式。在处理大量数据或者耗时操作时使用 Stream.parallel() 方法可以充分利用多核 CPU 的优势提高程序的性能。
Stream.parallel() 方法是将串行流转化为并行流的方法。通过该方法可以将大量数据划分为多个子任务交由多个线程并行处理最终将各个子任务的计算结果合并得到最终结果。使用 Stream.parallel() 可以简化多线程编程减少开发难度。
需要注意的是并行处理可能会引入线程安全等问题需要根据具体情况进行选择。
2、举一个简单的demo
定义一个list然后通过parallel() 方法将集合转化为并行流对每个元素进行i最后通过 collect(Collectors.toList()) 方法将结果转化为 List 集合。
使用并行处理可以充分利用多核 CPU 的优势加快处理速度。
public class StreamTest {public static void main(String[] args) {ListInteger list new ArrayList();for (int i 0; i 10; i) {list.add(i);}System.out.println(list);ListInteger result list.stream().parallel().map(i - i).collect(Collectors.toList());System.out.println(result);}
}我勒个去什么情况 这是大部分开发人员都会犯的小错误在上篇中提到过i 返回原来的值i 返回加1后的值。这谁都知道可是写的时候就不一定了因为你习惯了i写顺手了写的时候也是心不在焉一蹴而就了。
i改了i即可。
3、parallel()的优缺点
1优点
充分利用多核 CPU 的优势提高程序的性能可以简化多线程编程减少开发难度。
2缺点
并行处理可能会引入线程安全等问题需要根据具体情况进行选择并行处理需要付出额外的开销例如线程池的创建和销毁、线程切换等对于小数据量和简单计算而言串行处理可能更快。
4、何时使用parallel()
在实际开发中应该根据数据量、计算复杂度、硬件等因素综合考虑。
比如
数据量较大有1万个元素计算复杂度过大需要对每个元素进行复杂的计算硬件够硬比如多核CPU。
上一篇一个关于 i 和 i 的面试题打趴了所有人
哪吒多年工作总结Java学习路线总结搬砖工逆袭Java架构师。