多线程8

ops/2024/10/21 7:26:27/
java">void 取款(){int oldBalance =balance
if(!CAS(balance,oldBalance,oldBalance-500)){}}

在这个线程中如果变成了这样

java">void 取款(){int oldBalance =balancevoid 取款(){int oldBalance =balance
if(!CAS(balance,oldBalance,oldBalance-500)){}有人转账发生了500->1000。}
if(!CAS(balance,oldBalance,oldBalance-500)){}}

这两个东西不相等,就会产生bug,上述的过程就属于ABA问题的典型bug场景是非常高极端的情况

如何避免ABA问题呢??

核心思路是,使用账户余额判定,本身就不太科学.账户余额本身就属于"能加也能减”,就容易出现ABA问题,

引入"版本号”,约定版本号,只能加,不能减~~每次操作一次余额,版本号都要+1通过CAS判定版本号,就可以进一步的来完成上述的操作~~

一个版本号走一步

JUC中的常见类

Callable接口

java">public class Test {private  static int sum=0;public static void main(String[] args) throws InterruptedException {Thread t=new Thread(new Runnable() {@Overridepublic void run() {int result=0;for (int i = 0; i <=1000 ; i++) {result+=i;}sum=result;}});t.start();t.join();System.out.println(sum);}
}

java">    Thread t=new Thread(callable)

Callable不能直接填写到Thread构造方法中

java">import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test1 {public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Integer> callable=new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int result=0;for (int i = 0; i <10000 ; i++) {result+=i;}return result;}};//这是FutureTask的包装类FutureTask<Integer>futureTask=new FutureTask<>(callable);Thread thread=new Thread(futureTask);thread.start();thread.join();System.out.println(futureTask.get());}
}

FutureTask就像中间上来赚取差价。靠他们中间。

线程创建的方式:

1)继承Thread

2)使用Runnable

3)使用lambda

4)使用线程池/ThreadFactory

5)使用Callable

ReentrantLock

java">import java.util.concurrent.locks.ReentrantLock;public class Test2 {public static void main(String[] args) {ReentrantLock lock = new ReentrantLock();try {lock.lock();}finally {lock.unlock();}}
}

1.ReentrantLock提供了公平锁的实现synchronized只是非公平锁。

java">  ReentrantLock lock = new ReentrantLock(true);

2.ReentrantLock提供tryLock操作.

给加锁提供了更多的课操作空间尝试加锁,如果锁已经被获取到了,直接返回失败,而不会继续等待。

Synchronized都是遇到锁竞争,就阻塞等待.(死等)

tryLock除了直接返回这种形态之外还有一个版本,可以指定等待超时时间

3.synchronized是搭配waitnotify等待通知机制

ReentrantLock是搭配Condition类完成等待通知Condition要比waitnotify更强一点(多个线程wait,notify是唤醒随机的一个.Condition指定线程唤醒)

信号量Semaphore

信号量就是一个计数器,描述了可用资源的个数

围绕信号量有两个基本操作

1.P操作.计数器-1.申请资源

2.V操作.计数器+1.释放资源

通过Semaphore完成

java">import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class Test2 {private final static Semaphore semaphore = new Semaphore(1);public static void main(String[] args){ExecutorService pools = Executors.newCachedThreadPool();for (int i=0 ; i < 10;i++){final int index = i;Runnable run = new Runnable() {@Overridepublic void run() {try {semaphore.acquire();} catch (InterruptedException e) {e.printStackTrace();} finally {//使用完成释放锁semaphore.release();System.out.println("锁释放");}}};pools.execute(run);}pools.shutdown();}}

CountDownLatch

多线程下载.

把一个大的文件,拆分成多个部分.比如20个部分

每个线程都独立和人家服务器建立连接,分20个连接进行下载

等所有线程下载完毕之后,再结果进行合并.

CountDownLatch

java">import java.util.concurrent.CountDownLatch;public class Test3 {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(10);latch.countDown();latch.await();//await会阻塞等待,一直到countDown调用的次数,和构造方法指定的次数一致的时候,,await才会返回}
}

Vector自带了synchronized加锁不能保证线程一定安全

Stack继承自Vector,也自带了synchronized不加锁也不能确定线程一定不安全

Hashtable也是自带synchronized一定要具体代码具体分析~~

java"> Vector<String>vector=new Vector<>();void  func(){if(vector.size()>0){System.out.println(vector.get(0));}}

比如t1纟线程执行func到if之后t2线程把巴vector清空了回到t1继续执行,get(0)就出问题了,

java">  Collections.synchronizedList(new ArrayList)

给ArrayList这些集合类,套一层壳

壳上是给关键方法都加了synchronized就可以使ArrayList达到类似于Vector效果。

CopyOnWriteArrayList

写时拷贝

修改的同时,很多线程在读呢如果直接修改,不加任何处理意味着有的线程可能会读到200,3这种“中间情况。

写完之后,用新的数组的引用,代替旧的数组的引用(3|用赋值操作,是原子的)上述过程,没有任何加锁和阻塞等待,也能确保读线程不会读出“错误的数据旧的空间就可以释放了。

多线程使用队列

直接使用BlockingQueue即可.

HashMap是线程不安全的Hashtable是带锁的,是否就线程更安全呢??但是这个并不推荐使用

Hashtable加锁就是简单粗暴给每个方法加了synchronized.就相当于是针对this加锁.只要针对Hashtable上的元素进行操作,就都会涉及到锁冲突, 

 ConcurrentHashMap做出了优化

1.使用“锁桶”的方式,来代替“一把全局锁”,有效降低锁冲突的概率

 另一方面,看起来锁对象多了,实际上也不会产生更多的额外开销Java中每个对象都可以作为锁对象就只需要把synchronized加到链表

一个hash表,上面的hash桶的个数是非常多~~大部分的操作,都没有锁冲突了,(synchronized,如果不产生锁冲突,就是个偏向锁)

2.像hash表的size,即使你插入的元素是不同的链表上的元素,也会涉及到多线程修改同一个变量

3.针对扩容操作做了特殊优化

如果发现负载因子太大了,就需要扩容扩容是一个比较重量比较低效的操作。

化整为零.ConcurrentHashMap会在扩容的时候,搞两份空间.

一份是之前扩容之前的空间一份是扩容之后的空间接下来每次进行hash表的基本操作,都会把一部分数据从I旧空间搬运到新空间

搬的过程中:1.插入=>插入到新的上面2.删除=>新的日的都要删除3.查找=>新的日的都要查找

 java8之前,ConcurrentHashMap基于分段锁的方式实现的,

引l入若干个锁对象,每个锁对象管理若干个hash桶相比于Hashtable是进化,但是不如现在直接锁桶代码写起来更复杂


http://www.ppmy.cn/ops/4048.html

相关文章

量子密钥分发系统设计与实现(一):系统基本架构讨论

经过一段时间讨论&#xff0c;我们了解到量子密钥分发设备是当前量子保密通信系统的基础。从本文开始&#xff0c;我将开启量子密钥分发系统设计与实现系列&#xff0c;详细讨论量子密钥分发设备如何从0到1的搭建。 1.QKD系统总体讨论 QKD系统的核心功能就是为通信双方提供理论…

Windows下载使用nc(netcat)命令

‘nc’ 不是内部或外部命令&#xff0c;也不是可运行的程序&#xff1f; 点击链接地址&#xff0c;下载压缩包。 完成后解压 使用方式&#xff08;三种&#xff09;&#xff1a; 1、直接双击exe使用 2、把这个exe放到cmd启动的默认路径下 放到默认路径下&#xff0c;使用nc&a…

Linux引导过程与服务控制

Linux操作系统引导过程 排除启动类故障 服务控制及切换运行级别 优化启动过程 Linux引导过程 引导过程总览&#xff1a; 简化来说就是由开机自检 MBA引导 GRUB菜单 加载内核&#xff08;kernel&#xff09; init进程初始化等组成 Linux 操作系统的引导过程&…

DAY31-贪心算法| 455.分发饼干,376.摆动序列,53. 最大子序和

文章目录 455.分发饼干376.摆动序列53.最大子序和 455.分发饼干 文字讲解&#xff1a;分发饼干 视频讲解&#xff1a;分发饼干 状态&#xff1a;这题ok 思路&#xff1a; 代码&#xff1a; class Solution {public int findContentChildren(int[] g, int[] s) {if (s.length0…

vue中使用水印

1. 在utils下创建watermark.js const watermark {}/**** param {要设置的水印的内容} str* param {需要设置水印的容器} container* param {需要设置水印的每一块的宽度} canWidth* param {需要设置水印的每一块的高度} canHeight* param {需要设置水印的字体} canFont* para…

墨子web3时事周报

蚂蚁集团Web3研发进展与布局 国内Web3赛道的领军企业——蚂蚁集团&#xff0c;凭借其在前沿科技领域的深耕不辍&#xff0c;已在Web3技术研发疆域缔造了卓越战绩。特别是在引领行业革新的关键时刻&#xff0c;集团于今年四月末震撼推出了颠覆性的Web3全套解决方案&#xff0c…

移植speexdsp到OpenHarmony标准系统②

在linux上生成speexdsp的so动态链接库和.a静态链接库 make和make install后会生成speexdsp的.so动态链接库和.a静态链接库 make make install其中build/lib目录下&#xff1a; ├── libspeexdsp.a /*静态库*/ ├── libspeexdsp.la …

聊聊大模型的屏蔽词工程

概述 在做微调训练时&#xff0c;鉴于业务场景的需要&#xff0c;可能会存在微调数据集中含有敏感词汇&#xff0c;譬如&#xff1a;自杀、跳楼等。而开源模型可能没有做敏感词汇的屏蔽工程。因此可能就会出现不可预控的现象&#xff0c;而我遇到的是&#xff0c;当我输入敏感词…