Java多线程(3)---锁策略、CAS和JUC

目录

前言

一.锁策略

1.1乐观锁和悲观锁

⭐ 两者的概念

⭐实现方法

1.2读写锁

 ⭐概念

⭐实现方法

1.3重量级锁和轻量级锁

1.4自旋锁和挂起等待锁

⭐概念

⭐代码实现

1.5公平锁和非公平锁

1.6可重入锁和不可重入锁

二.CAS

2.1为什么需要CAS

2.2CAS是什么

⭐CAS的介绍

⭐CAS工作原理

2.3CAS存在的问题        

2.4CAS的应用

⭐实现原子类        

⭐实现自旋锁

2.5CAS的缺点

三.JUC

 3.1ReentrantLock类

3.2Semaphore类

3.3CountDownLatch类


🎁个人主页:tq02的博客_CSDN博客-C语言,Java,Java数据结构领域博主
🎥 本文由 tq02 原创,首发于 CSDN🙉
🎄 本章讲解内容:线程的策略锁、CAS和JUC

🎥学习专栏:  C语言         JavaSE       MySQL基础    

前言

        在上章的 多线程二 中,我们学习到为了线程安全,我们需要进行加锁操作,锁这个概念不仅仅只存在于Java当中,锁也分很多种类。CAS在多线程二的讲解中稍微提及过,至于JUC则是指java.util.concurrent的常见类。

一.锁策略

        锁策略一共有10种,在面试的过程当中也是非常重要的,我们需要了解锁策略的每一种。

在面试当中,你的面试官是会询问你的哦,所以为了自己的大钱途,努力学习吧!!!

1.1乐观锁和悲观锁

⭐ 两者的概念

  • 悲观锁: 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
  • 乐观锁:假设数据一般情况下不会产生并发冲突,所以在数据进行提交更新的时候,才会正式对数据是否产生并发冲突进行检测,如果发现并发冲突了,则让返回用户错误的信息,让用户决定如何去做。

抽象表达:

        悲观锁,就相当于学生向老师提问,但是学生认为老师不一定有空,因此先发个信息给老师,老师说有空,则立马去解答,如果没空(被其他线程加锁),则等待老师有空(解锁)。

        乐观锁,学生不认为老师很忙,直接去询问老师,结果2种,老师如果有空则会解答,没空就下次来询问。

实现方法

悲观锁:使用synchronized关键字来实现,正常的加锁行为。

乐观锁:添加一个版本号,通过在进行数据更新操作时,先读取数据并记录版本号,然后在更新数据时检查版本号是否一致。如果版本号一致,说明没有其他线程修改过数据,可以进行更新;如果版本号不一致,说明其他线程已经修改过数据,更新。

乐观锁Java代码实现:

public class Counter {private int count = 0;private int version = 0;    //版本号public void increment() {       while (true) {int currentVersion = version;if (compareAndSet(currentVersion)) {count++;break;}}}public int getCount() {return count;}public synchronized boolean compareAndSet(int expectVersion) {if (version == expectVersion) {version++;        //版本号相同时,执行一次操作+1return true;}return false;        //版本号不同,则返回false}}

compareAndSet方法实现了基于版本号的乐观锁。increment方法先读取当前的版本号,然后在一个while循环中不断尝试更新数据,如果compareAndSet方法返回true,则表示更新成功,否则需要继续重试。


结论:悲观锁通过加锁保护共享资源,保证线程安全。乐观锁则通过无锁编程的方式提高并发性能。开发人员需要根据实践场景选择适应的锁。

1.2读写锁

 ⭐概念

   多线程之间,数据的读取方之间不会产生线程安全问题,但数据的写入方互相之间以及和读者之间都需要进行互斥。如果两种场景下都用同一个锁,就会产生极大的性能损耗。所以读写锁因此而产生。

一个线程对于数据的访问, 主要存在两种操作: 读数据 和 写数据.

  • 两个线程都只是读一个数据, 此时并没有线程安全问题. 直接并发的读取即可.
  • 两个线程都要写一个数据, 有线程安全问题.
  • 一个线程读另外一个线程写, 也有线程安全问题

⭐实现方法

         读写锁将读操作和写操作区分对待,而为了实现读写锁,Java标准库提供了ReentrantReadWriteLock 类,在该类中又使用了2种类分别实现了读锁和写锁。

  • ReentrantReadWriteLock.ReadLock 类表示一个读锁. 这个对象提供了 lock / unlock 方法进行
    加锁解锁.
  • ReentrantReadWriteLock.WriteLock 类表示一个写锁. 这个对象也提供了 lock / unlock 方法进
    行加锁解锁.
     

ReentrantReadWriteLock.ReadLock 类代码实现:

import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadLockDemo {private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();private static ReentrantReadWriteLock.ReadLock readLock = lock.readLock();public static void main(String[] args) {new Thread(ReadLockDemo::read).start();new Thread(ReadLockDemo::read).start();}public static void read() {try {readLock.lock();    //加锁System.out.println(Thread.currentThread().getName() + "获取了读锁");// 执行读操作Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();} finally {readLock.unlock();    //解锁System.out.println(Thread.currentThread().getName() + "释放了读锁");}}
}

ReentrantReadWriteLock.WriteLock 类代码实现:

import java.util.concurrent.locks.ReentrantReadWriteLock;public class MyReadWriteLock {private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();public void writeData() {ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();writeLock.lock();    //加锁try {// 从文件或数据库中写入数据System.out.println(Thread.currentThread().getName() + " is writing data...");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {writeLock.unlock();    //解锁}}
}

结论读加锁和读加锁之间, 不互斥写加锁和写加锁之间, 互斥读加锁和写加锁之间, 互斥.

1.3重量级锁和轻量级锁

        所谓的重量和轻量,就是开销程度大和小。重量级锁:加锁的开销比较大(花的时间多、占用系统资源多).轻量级锁:加锁开销小(花的时间少、占用系统资源少)。

重量级锁:交给 OS 管理锁的争抢,释放 CPU 资源,ReentrantLock 类表示重量级锁

轻量级锁:JVM 自己管理锁的争抢(无锁,自旋锁),CPU资源不释放,实现基于CAS。

注:一个悲观锁可能是重量级锁、一个乐观锁可能是轻量锁

1.4自旋锁和挂起等待锁

⭐概念

        自旋锁是一种典型的 轻量级锁 的实现方式.
优点: 没有放弃 CPU, 不涉及线程阻塞和调度, 一旦锁被释放, 就能第一时间获取到锁.
缺点: 如果锁被其他线程持有的时间比较久, 那么就会持续的消耗 CPU 资源. 

        挂起等待锁是一种典型的 重量级锁 的实现方式

优点:避免线程的空轮询,确保在锁被释放后立即获取到锁,可以避免不必要的自旋浪费CPU资源。

缺点:增加了系统资源消耗和线程的等待时间。

⭐代码实现

自旋锁的代码实现:

import java.util.concurrent.atomic.AtomicReference;public class SpinLock {private AtomicReference<Thread> lock = new AtomicReference<>();public void lock() {Thread currentThread = Thread.currentThread();while (!lock.compareAndSet(null, currentThread)) {// 自旋等待}}public void unlock() {Thread currentThread = Thread.currentThread();lock.compareAndSet(currentThread, null);}
}

挂起等待锁代码实现:

public class WaitLockExample {private final Object lock = new Object();private boolean isLocked = false;public void foo() throws InterruptedException {synchronized(lock) {while(isLocked) {  //挂起等待中lock.wait();}// 执行线程的操作isLocked = true;}}public void bar() {synchronized(lock) {// 执行线程的操作isLocked = false;lock.notify();}}
}

1.5公平锁和非公平锁

        公平锁:遵循先来后到的原则,例如:线程A、B、C依次来,当A释放锁时,按顺序则下一个加锁的线程为B。

        非公平锁:不遵守先来后到的原则,例如:线程A、B、C依次来,当A释放锁时,结果下一个加锁的线程为C,而不是B

注:操作系统内部的线程调度就可以视为是随机的. 如果不做任何额外的限制, 锁就是非公平锁. 如果要想实现公平锁, 就需要依赖额外的数据结构, 来记录线程们的先后顺序.synchronized 是非公平锁.
 

1.6可重入锁和不可重入锁

        可重入锁:“可以重新进入的锁”,即允许同一个线程多次获取同一把锁。

情况:递归函数里有加锁操作,递归过程中这个锁会阻塞自己吗?不会,那么这个锁就是可重入锁而若是发生阻塞,那么自己阻塞自己,无法解锁,导致了死锁。 

Java中:以Reentrant开头命名的锁都是可重入锁,而且JDK提供的所有现成的Lock实现类,包括synchronized关键字锁都是可重入的。
      不可重入锁:只判断这个锁有没有被锁上,只要被锁上申请锁的线程都会被要求等待。实现简单


二.CAS

2.1为什么需要CAS

        多个线程同时访问锁,那么一些线程将被挂起,当线程恢复执行时,必须等待其它线程执行完他们的时间片以后才能被调度执行,在挂起和恢复执行过程中存在着很大的开销。锁还存在着其它一些缺点,当一个线程正在等待锁时,它不能做任何事。如果一个线程在持有锁的情况下被延迟执行,那么所有需要这个锁的线程都无法执行下去。如果被阻塞的线程优先级高,而持有锁的线程优先级低,将会导致优先级反转。
        CAS可以解决这一类弊端,鉴别线程冲突,一旦检测到冲突,就重复当前操作直到没有冲突为止。与锁相比,CAS会使得程序设计比较复杂,但是由于其天生免疫死锁(根本就没有锁,当然就不会有线程一直阻塞了),更为重要的是使用无锁的方式没有锁竞争带来的开销,也没有线程间频繁调度带来的开销,他比基于锁的方式有更优越的性能,所以在目前已经被广泛应用。
 

2.2CAS是什么

⭐CAS的介绍

        CAS机制全称compare and swap,翻译为比较并交换,是一种有名的无锁(lock-free)算法。只有一步原子操作,所以非常快。而且CAS避免了请求操作系统来裁定锁的问题,直接在CPU内部就完成了。

CAS工作伪代码:真实的 CAS 是一个原子的硬件指令完成的. 这个伪代码只是辅助理解

CAS是由CPU支持的原子操作,其原子性是在硬件层面进行保证的。 

注:一个线程的CAS先访问到内存,另一个后访问内存。


⭐CAS工作原理

CAS包含3个值:

  • 需要读写的内存位置(V)
  • 原来的值(A)
  • 期待更新的值(B)。

CAS操作逻辑如下:如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。

2.3CAS存在的问题        

ABA问题                                                                                                                                          因为CAS会检查旧值有没有变化,因此存在一个问题。比如一个旧值A变为了成B,然后再变成A,刚好在做CAS时检查发现旧值并没有变化依然为A,但是实际上的确发生了变化解决方案:沿袭数据库中常用的乐观锁方式,添加一个版本号可以解决。原来的变化路径A->B->A就变成了1A->2B->3C。Java 1.5后的atomic包中提供了AtomicStampedReference来解决ABA问题,解决思路就是这样的。

自旋时间过长                                                                                                                                    使用CAS时非阻塞同步,也就是说不会将线程挂起,会自旋(无非就是一个死循环)进行下一次尝试,如果这里自旋时间过长对性能是很大的消耗。如果JVM能支持处理器提供的pause指令,那么在效率上会有一定的提升。

只能保证一个共享变量的原子操作                                                                                                 当对一个共享变量执行操作时CAS能保证其原子性,如果对多个共享变量进行操作,CAS就不能保证其原子性。

解决方案:利用对象整合多个共享变量,即一个类中的成员变量就是这几个共享变量。然后将这个对象做CAS操作就可以保证其原子性。atomic中提供了AtomicReference来保证引用对象之间的原子性。

2.4CAS的应用

⭐实现原子类        

Java标准库中提供了 java.util.concurrent.atomic 包, 里面的类都是基于这种方式来实现的.
        典型的就是 AtomicInteger 类. 其中的 getAndIncrement 相当于 i++ 操作

AtomicInteger atomicInteger = new AtomicInteger(0);atomicInteger.getAndIncrement(); // i++atomicInteger.incrementAndGet(); //++iatomicInteger.getAndDecrement(); //i--atomicInteger.decrementAndGet(); //--i

代码示例: 

private static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {// count++count.getAndIncrement();             }});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();}});t1.start();t2.start();System.out.println(count.get());  //输出结果:100000}

如上述代码,此时就不会存在相加时,覆盖相同的值了,因此结果为100000.

⭐实现自旋锁

        基于 CAS 实现更灵活的锁, 获取到更多的控制权.

自旋锁的代码实现:

public class SpinLock {
private Thread owner = null;
public void lock(){// 通过 CAS 看当前锁是否被某个线程持有.// 如果这个锁已经被别的线程持有, 那么就自旋等待.// 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程.while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}
}

通过CAS判定出,当前变量的自增过程当中,是否有其他线程穿插进来了。

2.5CAS的缺点

  1. 一次性只能保证一个共享变量的原子性                                                                                   ​当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。
  2. 循环会耗时                                                                                                                             我们可以看到getAndAddInt方法执行时,如果CAS失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。

​ 在并发冲突概率大的高竞争环境下,如果CAS一直失败,会一直重试,CPU开销较大。针对这个问题的一个思路是引入退出机制,如重试次数超过一定阈值后失败退出。当然,更重要的是避免在高竞争环境下使用乐观锁。

     3.存在ABA问题


三.JUC

        JUC工具包全名:java.util.concurrent,专门处理线程的工具包,从jdk1.5开始出现。

目的:为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题! 

而JUC中常见的类有:ReentrantLock :可重入锁;Semaphore :信号量;
                                   ountDownLatch :计数器;   CyclicBarrier :循环屏障。

 3.1ReentrantLock类

ReentrantLock类:可重入互斥锁. 和 synchronized 定位类似, 都是用来实现互斥效果, 保证线程安全.

// ReentrantLock 的构造方法
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}

用法:

  1. lock(): 加锁, 如果获取不到锁就死等;
  2. trylock(超时时间): 加锁, 如果获取不到锁, 等待一定的时间之后就放弃加锁;
  3. unlock(): 解锁。

与synchronize的区别:

  1. synchronized 是一个关键字, 是 JVM 内部实现的(大概率是基于 C++ 实现). ReentrantLock 是标准库的一个类, 在 JVM 外实现的(基于 Java 实现).
  2. synchronized 使用时不需要手动释放锁. ReentrantLock 使用时需要手动释放. 使用起来更灵活,但是也容易遗漏 unlock.
  3. synchronized 在申请锁失败时, 会死等. ReentrantLock 可以通过 trylock 的方式等待一段时间就
  4. 放弃.
  5. synchronized 是非公平锁, ReentrantLock 默认是非公平锁. 可以通过构造方法传入一个 true 开启公平锁模式

那么如何选择哪个锁呢?

  • 锁竞争不激烈的时候, 使用 synchronized, 效率更高, 自动释放更方便.
  • 锁竞争激烈的时候, 使用 ReentrantLock, 搭配 trylock 更灵活控制加锁的行为, 而不是死等.
  • 如果需要使用公平锁, 使用 ReentrantLock.
     

3.2Semaphore类

Semaphore类:信号量, 用来表示 “可用资源的个数”,本质上就是一个计数器。该类用于控制信号量的个数,构造时传入个数。总数就是控制并发的数量。

抽象解释:五双筷子,A拿了一双,则显示还有4双可用,A放回,则显示还有5双可用。若是5双筷子都被别人拿了,则禁止别人拿取筷子,等待别人放回。

import java.util.concurrent.Semaphore;public class SemaphoreTest {public static void main(String[] args) {// 创建Semaphore对象,设置许可数为3Semaphore semaphore = new Semaphore(3);// 创建10个线程for (int i = 1; i <= 10; i++) {MyThread thread = new MyThread(semaphore, i);new Thread(thread).start();}}static class MyThread implements Runnable {private Semaphore semaphore;private int threadNum;public MyThread(Semaphore semaphore, int threadNum) {this.semaphore = semaphore;this.threadNum = threadNum;}@Overridepublic void run() {try {// 获取许可,若还有许可数,则占用,若无则堵塞semaphore.acquire();System.out.println("线程" + threadNum + "获取到了许可");Thread.sleep(2000); // 模拟线程执行一段耗时的操作} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放许可semaphore.release();System.out.println("线程" + threadNum + "释放了许可");}}}}

当一个线程调用 acquire() 方法时,计数器就会减一,当计数器为0时,它就会阻塞。当一个线程调用 release() 方法时,它将增加计数器的值,然后唤醒一个被阻塞的线程。

3.3CountDownLatch类

计数器:同时等待 N 个任务执行结束。例如田径比赛,只有所有人都通过终点,才能公布成绩。

public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {// 创建计算器CountDownLatch countDownLatch = new CountDownLatch(5);// 创建线程池ExecutorService service = Executors.newFixedThreadPool(5);// 创建新线程执行任务for (int i = 1; i <= 5; i++) {service.submit(() -> {Thread currThread = Thread.currentThread();System.out.println(currThread.getName() + "开始起跑");int runTime = new Random().nextInt(5) + 1;try {TimeUnit.SECONDS.sleep(runTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(currThread.getName() + "到达终点,用时:" + runTime);countDownLatch.countDown();  //在 CountDownLatch 内部的计数器同时自减.});}countDownLatch.await();  //阻塞等待所有任务执行完毕System.out.println("比赛结果宣布!");}
}

在代码当中,只有线程全部结束时,才能公布最后的结果


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1382022.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

互联网DPI

DPI是Deep packet inspection. 基于数据包的深度检测技术&#xff0c;针对不同的网络应用层载荷&#xff08;例如HTTP、DNS等&#xff09;进行深度检测&#xff0c;通过对报文的有效载荷检测决定其合法性。&#xff08;From Baidu&#xff09; 深度检测是与普通的报文分析层次…

模糊PID(模糊规则表)

模糊PID的模糊化相关内容,请参看下面的博客文章: PLC模糊控制模糊PID(梯形图实现+算法分析)_RXXW_Dor的博客-CSDN博客博途PLC的模糊PID控制详细内容请查看下面的博客文章:Matlab仿真+博途PLC模糊PID控制完整SCL源代码参考(带模糊和普通PID切换功能)_博途怎么实现模糊pid_…

如何取消Barracuda Reputation的IP 黑名单?

客户来信反映说邮件发送失败&#xff0c;退信内容如下&#xff1a; reason: 554 Service unavailable; Client host [*********邮件服务器] blocked using Barracuda Reputation; http://bbl.barracudacentral.com/q.cgi?ip116.231.5.113) 解决方法参考如下说明: 1.当你采用ou…

win10 高DPI 高分屏 解决模糊问题的方法

本人使用的是 win10 1809的版本 使用高分辨率的显示器时&#xff0c;发现打开部分win7软件很模糊&#xff0c;分分钟亮瞎眼&#xff0c;在网上找遍了相关的设置方法&#xff08;比如使用字体修改软件&#xff0c;使用修改DPI修改软件等&#xff09;&#xff0c;没有得到我要的理…

【技巧】修改windows10在高分屏下的应用的dpi

我使用的是surface pro3&#xff0c;拥有2K的分辨率。 同时&#xff0c;我很热衷新事物所以&#xff0c;我使用了windows10 的最新版&#xff0c;并且启用了高dpi设置&#xff08;150左右&#xff09;。 之后就发现一些老软件如photoshop、Articulate Storyline、百度网盘等应…

第十七届全国大学生智能车竞赛华南赛区报名信息

学校组别队名组员指导教师 华南理工大学四轮电磁组华工旋风队王熙来陈安邓晓燕   艾一帆     张家瑜   四轮摄像头组华工白弧队黄岳鹏陈安邓晓燕   梁健铭     张武江   多车编队组华工冰魄队李茂霖陈安邓晓燕   亢文帅     董嘉豪     黄…

第五届湖南省机器人大赛暨第十四届湖南省智能汽车大赛名单

简 介&#xff1a; 本文汇总了第五届湖南省智能车竞赛的基本信息。感谢中南大学王击老师发送过来的信息。 关键词&#xff1a; 湖南省智能车竞赛&#xff0c;智能车竞赛 #mermaid-svg-Bl4gxd2xsRwJqsTI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-s…

第十七届全国大学生智能车竞赛线上比赛直播链接

01 直播信息 惠州学院赛点比赛时间安排表以及直播链接 7月25日上午组别学校&队伍名称时间直播B站直播链接 四轮电磁东江-白夜&#xff08;惠州学院&#xff09;9:00-9:20直播1https: b23.tv FnIhJ5g 腾讯会议&#xff1a;976-769-477 四轮摄像头一路顺风&#xff08;东软…

SCAU操作系统知识点之(五)并发:互斥和同步

1、互斥的概念 互斥&#xff1a;当一个进程在临界区访问共享资源时&#xff0c;其他进程不能进入该临界区访问任何共享资源。 用硬件实现进程互斥时&#xff0c;中断禁用适于单 CPU 系统&#xff0c;多 CPU 系统可使用专用机器指令。 2、临界资源与临界区 临界区&#xff1a;一…

iOS 组件化的三种方案

组件化 本文主要介绍iOS组件化的三种方案 1、常⽤的三种方案 URL SchemeTarget - ActionProtocol - Class 匹配 1.1、 URL Scheme路由 使 URL 处理本地的跳转通过中间层进⾏注册 & 调⽤ &#xff08;load方法里把被调用者注册到中间层&#xff09;注册表⽆需使用反射非…

《最强大模型平台上线,被很多行业“盯”上了》

千帆大模型 1、国内最多的模型2、国内最全的Prompt模板3、总结 千帆大模型平台是面向企业开发者的一站式大模型开发及服务运行平台&#xff0c;也是百度智能云推出的全球首个一站式企业级大模型平台。在提供全套文心大模型服务的基础上&#xff0c;还支持第三方开源大模型、各种…

【2020年底攻略】支付宝沾沾卡怎么获得 沾沾卡获取攻略分享

沾福气卡是支付宝中的一个特殊卡片&#xff0c;用这个新卡有机会复制朋友的任何一张卡牌&#xff0c;很多玩家不知道如何获取这张卡&#xff0c;下面来为大家带来的介绍。 沾福气卡怎么获得 1月28日-2月4日18点期间&#xff0c;每日手臂付款可以领取一张沾福气卡&#xff1b;…

2021支付宝集五福【攻略】!!!

一年一度的支付宝集五福在2月1号的凌晨开始了&#xff0c;虽然一年比一年瓜分的少&#xff0c;但不知不觉集福卡成了过年最佳的消遣娱乐方式了。活动从2月1日开始至1月11日结束。 零、额外福利 额外福卡二维码扫福器下载地址&#xff1a;https://syx0226.lanzous.com/iOP2Zl5w…

随机送一张花花卡跟一张敬业卡

马云的福字火了&#xff0c;猪肉铺大叔你也火了……马云福字是什么梗&#xff1f;之前马云曾写过一个福字&#xff0c;福中有田有猪有网有支付宝&#xff0c;昨天&#xff0c;有网友表示&#xff0c;一位菜市场的猪肉老板大叔对这个福字很中意&#xff0c;在店铺前挂出了这个福…

分割一切模型 Fast SAM C++推理部署---onnxruntime(有核心代码)

Fast SAM C推理部署—onnxruntime 核心源代码在结尾处 晓理紫 0 XX开局一张图&#xff0c;剩下… 本文记录只为日后更好学习 1 Fast SAM 简介 Fast SAM是仅使用SAM作者发布的SA-1B数据集的2%进行训练的CNN任意分割模型。FastSAM的性能与SAM方法相当&#xff0c;运行速度提高了…

支付宝五福53张自动领取程序 v2021

简介&#xff1a; 临近过年&#xff0c;身边的朋友们都开始参加支付宝一年一度的集五福活动了&#xff01;今天小编带来的这款支付宝五福53张自动领取程序能够帮助集福的朋友们更加轻松地完成任务&#xff0c;让用户一键完成53个任务并自动获取福卡&#xff0c;非常方便&#…

2920集五福_2020年支付宝集五福攻略

支付宝2020扫福活动在今天也就是1月13日开始啦&#xff0c;听说&#xff0c;居然有2.4万人集齐了吗&#xff0c;也太快了吧&#xff01;有人好奇&#xff0c;2020年支付宝集五福活动规则&#xff0c;有什么新玩法。不过不少小伙伴们比较关心的是2020每天可以扫几张福&#xff1…

2020 春节集五福最详细收集攻略

本文由葡萄城技术团队于博客原创并首发 转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 一年一度的支付宝集五福活动已经开始了&#xff0c;不知从什么时候开始&#xff0c;集五福已经成为了惯例…

已有一万名快手用户集齐好运卡获得六六六早鸟红包,还可再分一亿

“谁要来沾幸运的吗&#xff01;我已经集齐了&#xff01;“ “天呐&#xff0c;马上就要到一万人&#xff01;谁能让我沾一沾幸运&#xff01;“ 伴随着超话里网友们热火朝天的讨论&#xff0c;快手「集好运中国福」活动也终于迎来了第1万个集齐五张好运卡的幸运用户。 据了…

支付宝集五福可以开“外挂”? 70万人秒集齐!

点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐] 2月1日零点&#xff0c;2021年支付宝集五福活动正式开始&#xff0c;打响“年味”第一枪&#xff01; 我稍微看了看&#xff0c;今年的集福难度更低&#xff0c;生怕你集不全似的给各种“外挂”&#xff0c;开始13小时&am…