JUC并發編程(JUC核心類、TimeUnit類、原子操作類、CASAQS)附帶相關面試題

目錄

1.JUC并發編程的核心類

2.TimeUnit(時間單元)

3.原子操作類

4.CAS 、AQS機制


1.JUC并發編程的核心類

雖然java中的多線程有效的提升了程序的效率,但是也引發了一系列可能發生的問題,比如死鎖,公平性、資源管理以及如何面對線程安全性帶來的諸多危害。為此,java就提供了一個專門的并發編程包java.util.concurrent(簡稱JUC)。此包能夠有效的減少了競爭條件和死鎖問題。

以下介紹JUC包中核心的類

類名描述
ExecutorExecutor 是一個接口,定義了一種執行任務的方式,其目的是將任務的提交與任務的執行解耦。
ExecutorServiceExecutorServiceExecutor 的子接口,提供了更豐富的功能,例如線程池管理和任務提交等。
ScheduledExecutorServiceScheduledExecutorServiceExecutorService 的子接口,可以按照計劃(時間或延遲)來執行任務。
CompletionServiceCompletionService 是一個用于異步執行任務并獲取已完成任務結果的框架。
CallableCallable 是一個代表可以返回結果或拋出異常的任務的接口。它類似于 Runnable 接口,但具有返回值。
FutureFuture 是一個可用于獲取異步計算結果的接口。
ReentrantLockReentrantLock 是一個可重入鎖,它提供了更靈活的同步控制和更高級別的功能。
BlockingQueueBlockingQueue 是一個支持阻塞操作的隊列,提供了線程安全的生產者-消費者模式的實現。
CountDownLatchCountDownLatch 是一個同步輔助類,允許一個或多個線程等待其他線程完成操作后再繼續執行。
CyclicBarrierCyclicBarrier 是一個同步輔助類,使得一組線程能夠互相等待,直到所有線程都達到某個公共屏障點。


2.TimeUnit(時間單元)

這個類能夠非常好的讓我們實現各種時間之間的轉換。TimeUnit類的是枚舉類,里面有DAYS(天),HOURS(小時),MINUTES(分鐘),SECONDS(秒),MILLISECONDS(毫秒),NANNOSECONDS(納秒)

TimeUnit類中常用的方法:

方法簽名描述
public long convert(long sourceDuration, long srcDuration)該方法用于將給定的時間源持續時間轉換為目標持續時間。
public void sleep(long timeout) throws InterruptedException該方法使當前線程進入休眠狀態,暫停執行一段指定的時間(以毫秒為單位)。如果在休眠期間中斷了線程,則會拋出 InterruptedException 異常。

具體應用案例:

1.時間轉換與輸出一個月后的日期

package Example2101;import java.util.Date;
import java.util.concurrent.TimeUnit;public class javaDemo {public static void main(String[] args) {
//        五個小時時間long hours = 5;
//        通過SECONDS類將5個小時轉為秒long seconds = TimeUnit.SECONDS.convert(hours,TimeUnit.HOURS);System.out.println(seconds);//        獲取當前時間long now = System.currentTimeMillis();long furture = now + TimeUnit.MILLISECONDS.convert(30,TimeUnit.DAYS);System.out.println("Now Time is"+new Date(now));Date futureDay = new Date(furture);System.out.println("after mounth time is"+futureDay);}
}

?

案例2:定義一個鬧鐘,這個鬧鐘在5天后會自動發送消息

這種鬧鐘形式可以通過線程的睡眠機制進行完成,但是一般情況下如果使用線程的睡眠Thread.sleep()里面放的是毫秒,如果要睡眠五天,那么需要設置的數值會非常非常大的,所以可以使用TimeUnit類的睡眠方法實現自定義睡眠。

package Example2102;import java.util.concurrent.TimeUnit;public class javaDemo {public static void main(String[] args) {new Thread(()->{try {
//                通過TimeUnit下的Days類的sleep函數定義五天時間TimeUnit.DAYS.sleep(5);System.out.println("鬧鐘響了!!!!!!");}catch (InterruptedException e){e.printStackTrace();}},"鬧鐘").start();}
}

3.原子操作類

問題引出:一般情況下如果多線程進行競爭一個變量時候會引發數據錯亂的問題。比如多線程下售票員售票案例,由于多個線程競爭,一張票可能已經被賣出去了,但是其他的售票員并不知道,繼續售賣同一張票。在之前的時候我們通過了Sychronized()同步位解決了這個問題。但是用這個方法也有不小的弊端,那就是程序效率會大大下降。為此JUC提供了一個新的方式解決這個問題,那就是原子操作類。

首先理解原子性,原子是不可分割的最小物體,在編程中是指一種操作要么做了,要么不做。不可以中斷的一種操作。原子操作類具有更高效率,更安全,更簡單用法

原子操作類分為很多類,大致分為4類:

基本類型:AtomicInteger 、AtomicLong、AtomicBoolean

數組類型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

引用類型:AtomicReference、AtomicStampedReference、AtomicMarkableReference;

對象屬性修改類型:

AtomicIntegerFieldUpdater;AtomicLongFiledUpdater;AtomicReferenceFieldUpdater;

?1.基本類型的原子操作類

基本類型:AtomicInteger 、AtomicLong、AtomicBoolean

基本類型之間的操作是差不多的,這里用AtomicLong舉例

AtomicLong的常用方法

方法描述
AtomicLong(long initValue)創建一個新的AtomicLong實例,并設置初始值為initValue。
get()獲取當前存儲在AtomicLong中的值。
set(long newValue)將AtomicLong的值設置為newValue。
getAndIncrement()先獲取當前存儲在AtomicLong中的值,然后將AtomicLong的值增加1。返回先前的值。
setAndIncrement()將AtomicLong的值增加1。返回增加前的值。
decrementAndGet()將AtomicLong的值減少1,并返回減少后的值。

使用類方法的關鍵就在于熟悉add(增加) decrement(自減)increment(自增) set(設置值) get(獲取類內部的數據) 方法就是這幾個操作之間的組合

案例代碼:多個售票員售賣100張票

package Example2103;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;public class javaDemo {public static void main(String[] args) {
//        創建原子操作類AtomicInteger ticket = new AtomicInteger(6);AtomicInteger flag = new AtomicInteger(1);//標志還有票//        創建三個線程進行售票for (int i =0;i<3;i++){new Thread(()->{while (ticket.get()>0){System.out.println("售票員"+Thread.currentThread().getName()+"售賣第"+ticket.decrementAndGet()+"張票");try {
//                        設置兩秒睡眠TimeUnit.SECONDS.sleep(2);}catch (Exception e){e.printStackTrace();}
//                    如果沒有票了就將標志位的值設置為0,表示沒有票了if (ticket.get() == 0){flag.set(0);System.out.println("賣完了");}}}).start();}}
}

?

?可以看到即使沒有使用同步機制也實現了同步的效果。

2.數組原子操作類

數組原子操作類有:AtomicArrayInteger AtomicLongArray AtomicReferenceArray(對象數組)

由于三者這件的使用區別不大,所以這里展示AtomicReferenceArray

AtomicReferenceArray常用方法:

方法描述
AtomicReferenceArray(int length)構造一個指定長度的AtomicReferenceArray對象。
AtomicReferenceArray(E[] array)使用給定數組初始化AtomicReferenceArray對象。
int length()返回AtomicReferenceArray的長度(即元素個數)。
boolean compareAndSet(int index, E expect, E update)將指定索引位置的元素與期望值進行比較,如果相等,則將其更新為新的值。該操作是原子性的,返回是否更新成功。
E get(int index)獲取指定索引位置的元素的值。
void set(int index, E newValue)設置指定索引位置的元素的值為newValue。
E getAndSet(int index, E newValue)獲取指定索引位置的元素的當前值,并將其設置為newValue。

?案例代碼:

package Example2104;import java.util.concurrent.atomic.AtomicReferenceArray;public class javaDemo {public static void main(String[] args) {String data[] = new String[]{"王二狗","180","130"};
//        初始化AtomicReferenceArray<String> array = new AtomicReferenceArray<String>(data);
//        對象數組的操作System.out.println("身高是:"+array.get(1));array.set(2,"150");System.out.println(array.get(0)+"在拼命鍛煉后體重變成:"+array.get(2));
//        篩選如果名字是王二狗的自動改名王二array.compareAndSet(0,"王二狗","王二");System.out.println("改名后名字叫"+array.get(0));}
}

?3.引用原子操作類

引用類型:AtomicReference、AtomicStampedReference、AtomicMarkableReference;

其中AtomicReference是可以直接引用數據類型的原子性操作

下面是AtomicReference的常用方法:

方法描述
AtomicReference()無參構造方法,創建一個初始值為null的AtomicReference對象。
V get()獲取當前AtomicReference對象持有的值。
void set(V newValue)設置AtomicReference對象的值為newValue。
boolean compareAndSet(V expect, V update)將AtomicReference對象的值與期望值expect進行比較(==比較),如果相等,則將其更新為新值update。該操作是原子性的,返回是否更新成功。
V getAndSet(V newValue)先獲取當前AtomicReference對象的值,然后將其設置為newValue,并返回原來的值。

案例代碼:使用AtomicReference進行引用操作

package Example2106;import java.util.concurrent.atomic.AtomicReference;
// 創建普通人類
class Person{private int age;private String name;private int id;Person(int age,String name,int id){this.age = age;this.name = name;this.id = id;}
}public class javaDemo {public static void main(String[] args) {Person person1 = new Person(18,"張三",001);Person person2 = new Person(20,"王思",1002);
//        傳入person1對象AtomicReference<Person> person = new AtomicReference<Person>(person1);
//        輸出對象地址System.out.println(person.get());
//        更改引用對象person.set(person2);System.out.println(person.get());}
}

AtomicStampedReference 基于版本號的數據引用。其中版本號是自己定義的int數據類型

下面是AtomicStampedReference的常用方法:

方法描述
AtomicStampedReference(V initRef, int initStamp)構造一個AtomicStampedReference對象,初始引用值為initRef,初始標記值(戳)為initStamp。
V getReference()獲取當前AtomicStampedReference對象持有的引用值。
void set(V newRef, int newStamp)設置AtomicStampedReference對象的引用值為newRef,標記值(戳)為newStamp。
boolean compareAndSet(V expectRef, V newRef, int expectStamp, int newStamp)將AtomicStampedReference對象的引用值與期望值expectRef、標記值(戳)與期望值expectStamp進行比較,如果相等,則將其更新為新值newRef和newStamp。該操作是原子性的,返回是否更新成功。
int attemptStamp(V expectedReference, int newStamp)如果當前引用值等于expectedReference,則嘗試將標記值(戳)更新為newStamp。如果更新成功,返回新的標記值(戳),否則返回當前標記值。
int getStamp()獲取當前AtomicStampedReference對象持有的標記值(戳)。

案例代碼:

package Example2107;import java.util.concurrent.atomic.AtomicStampedReference;class Draw{private String content = "";private String autor = "";private String title ="";Draw(String content,String autor,String title){this.content =content;this.autor = autor;this.title = title;}public void setContent(String content) {this.content = content;}public String getContent() {return content;}
}
public class javaDemo {public static void main(String[] args) {Draw  draw1= new Draw("","alphaMilk","JUC并發編程原子操作類");
//        初始化內容,版本號為1AtomicStampedReference<Draw> atomicDraw = new AtomicStampedReference<Draw>(draw1,1);System.out.println(atomicDraw.getReference());
//        更新內容,版本號更改draw1.setContent("Hello,word");atomicDraw.set(draw1,2);
//        獲取當前版本System.out.println(atomicDraw.getStamp());}
}

AtomicMarkableReference與AtomicStampedReference的區別在于,一個是設置boolean類型的初始化標記,一個多設置的是int類型版本號

下面是AtomicMarkableReference的常用方法:

方法描述
AtomicMarkableReference(V initRef, boolean initMark)構造一個AtomicMarkableReference對象,初始引用值為initRef,初始標記值為initMark。
V getReference()獲取當前AtomicMarkableReference對象持有的引用值。
boolean isMarked()判斷當前AtomicMarkableReference對象是否被標記。
boolean compareAndSet(V expectRef, V newRef, boolean expectMark, boolean newMark)將AtomicMarkableReference對象的引用值與期望值expectRef、標記值與期望值expectMark進行比較,如果相等,則將其更新為新值newRef和newMark。該操作是原子性的,返回是否更新成功。
void set(V newRef, boolean newMark)設置AtomicMarkableReference對象的引用值為newRef,標記值為newMark。
boolean attemptMark(V expectedReference, boolean newMark)如果當前引用值等于expectedReference,則嘗試將標記值更新為newMark。如果更新成功,返回true,否則返回false。

案例代碼:

一個班統計同學是否交了班費

package Example2108;import java.util.concurrent.atomic.AtomicMarkableReference;class  Student{private String name;private int id;Student(String name,int id){this.name = name;this.id = id;}
}
public class javaDemo {public static void main(String[] args) {Student stu1 = new Student("王一",001);Student stu2 = new Student("張二蛋",002);
//        王一交過班費AtomicMarkableReference<Student> atoStu = new AtomicMarkableReference<Student>(stu1,true);System.out.println(atoStu.getReference());if (atoStu.isMarked()){System.out.println("該同學交過班費");}else System.out.println("該同學尚未交過班費");
//        張二蛋沒有交班費atoStu.set(stu2,false);System.out.println(atoStu.getReference());if (atoStu.isMarked()){System.out.println("該同學交過班費");}else System.out.println("該同學尚未交過班費");}
}

4.對象屬性修改原子類

?AtomicIntegerFieldUpdater;AtomicLongFiledUpdater;AtomicReferenceFieldUpdater;

這三個類的實現原理基本差不多,所以將用AtomicIntegerFieldUpdater舉例:

以下是AtomicIntegerFieldUpdater類的常用方法:

int addAndGet(T obj, int data)將指定對象obj的字段值與data相加,并返回相加后的結果。
boolean compareAndSet(T obj, int expect, int update)將指定對象obj的字段值與期望值expect進行比較,如果相等,則將其更新為新值update。返回是否更新成功。
int get(T obj)獲取指定對象obj的字段值。
int getAndSet(T obj, int newValue)獲取指定對象obj的字段值,并將其設置為新值newValue。
int decrementAndGet(T obj)將指定對象obj的字段值減1,并返回減1后的結果。
int incrementAndGet(T obj)將指定對象obj的字段值加1,并返回加1后的結果。

?案例代碼:

package Example2109;import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;class Book{volatile long id;volatile String name;Book(long id, String name){this.id = id;this.name = name;}}public class javaDemo {public static void main(String[] args) {Book book1 = new Book(114514,"Java從入門到入土");AtomicReferenceFieldUpdater<Book,String> bookmanger = AtomicReferenceFieldUpdater.newUpdater(Book.class,String.class,"name");System.out.println("更新前書本名稱為:"+bookmanger.get(book1));bookmanger.set(book1,"Java從入門到項目實戰");System.out.println("更新后書本名稱為:"+bookmanger.get(book1));}
}

?


4.CAS 、AQS機制

CAS是一條CPU并發原語。它的功能是判斷某個內存某個位置的值是否相等,如果是則改為新的值,這個操作過程屬于原子性操作。

CAS是樂觀鎖,是一種沖突重試機制,在并發競爭不是很劇烈的情況下,其操作性能會好于悲觀鎖機制(Synchronization同步處理)

*面試題為什么說 Synchronized 是一個悲觀鎖?樂觀鎖的實現原理又是什么?什么是 CAS,它有什么特性?

  1. Synchronized的并發策略是悲觀的,不管是否產生競爭,任何數據的操作都必須加鎖。
  2. 樂觀鎖的核心是CAS,CAS包括內存值、預期值、新值,只有當內存值等于預期值時,才會將內存值修改為新值。

*面試題:樂觀鎖一定就是好的嗎?

  1. 樂觀鎖認為對一個對象的操作不會引發沖突,所以每次操作都不進行加鎖,只是在最后提交更改時驗證是否發生沖突,如果沖突則再試一遍,直至成功為止,這個嘗試的過程稱為自旋。
  2. 樂觀鎖沒有加鎖,但樂觀鎖引入了ABA問題,此時一般采用版本號進行控制;
  3. 也可能產生自旋次數過多問題,此時并不能提高效率,反而不如直接加鎖的效率高;
  4. 只能保證一個對象的原子性,可以封裝成對象,再進行CAS操作;

*面試題:volatile 關鍵字的作用

對于可見性,Java 提供了 volatile 關鍵字來保證可見性和禁止指令重排。 volatile 提供 happens-before 的保證,確保一個線程的修改能對其他線程是可見的。當一個共享變量被 volatile 修飾時,它會保證修改的值會立即被更新到主存,當有其他線程需要讀取時,它會去內存中讀取新值。

從實踐角度而言,volatile 的一個重要作用就是和 CAS 結合,保證了原子性,詳細的可以參見 java.util.concurrent.atomic 包下的類,比如 AtomicInteger。

volatile 常用于多線程環境下的單次操作(單次讀或者單次寫)。
?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36119.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36119.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36119.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【100天精通python】Day34:使用python操作數據庫_ORM(SQLAlchemy)使用

目錄 專欄導讀 1 ORM 概述 2 SQLAlchemy 概述 3 ORM&#xff1a;SQLAlchemy使用 3.1 安裝SQLAlchemy&#xff1a; 3.2 定義數據庫模型類&#xff1a; 3.3 創建數據表&#xff1a; 3.4 插入數據&#xff1a; 3.5 查詢數據&#xff1a; 3.6 更新數據&#xff1a; 3.7 刪…

C/C++中volatile關鍵字詳解

1. 為什么用volatile? C/C 中的 volatile 關鍵字和 const 對應&#xff0c;用來修飾變量&#xff0c;通常用于建立語言級別的 memory barrier。這是 BS 在 "The C Programming Language" 對 volatile 修飾詞的說明&#xff1a; A volatile specifier is a hint to a…

【Git】 git push origin master Everything up-to-date報錯

hello&#xff0c;我是索奇&#xff0c;可以叫我小奇 git push 出錯&#xff1f;顯示 Everything up-to-date 那么看看你是否提交了message 下面是提交的簡單流程 git add . git commit -m "message" git push origin master 大多數伙伴是沒寫git commit -m "…

AI自動駕駛

AI自動駕駛 一、自動駕駛的原理二、自動駕駛的分類三、自動駕駛的挑戰四、自動駕駛的前景五、關鍵技術六、自動駕駛的安全問題七、AI數據與自動駕駛八、自動駕駛的AI算法總結 自動駕駛技術是近年來備受關注的熱門話題。它代表了人工智能和機器學習在汽車行業的重要應用。本文將…

UML之四種事物

目錄 結構事物 行為事物 分組事物&#xff1a; 注釋事物 結構事物 1.類(Class) -類是對一組具有相同屬性、方法、關系和語義的對象的描述。一個類實現一個或多個接口 2.接口(interface) -接口描述 了一個類或構件的一個服務的操作集。接口僅僅是定義了一組操作的規范&…

案例16 基于Spring Boot實現學生新增案例

基于Spring Boot實現學生新增。 1. 創建Spring Boot項目 創建Spring Boot項目&#xff0c;項目名稱為case16-springboot-student01。 ? 2. 設置項目信息 ? 3. 選擇依賴 選擇Lombok ? 選擇Spring Web ? 4. 設置項目名稱 ? 5. Maven依賴 <?xml version"1.0&qu…

Nature子刊 |腸道宏病毒組揭示百歲老人長壽秘訣

發表期刊&#xff1a;nature microbiology 發表時間&#xff1a;2023 影響因子&#xff1a;28.3 DOI: 10.1038/s41564-023-01370-6 研究背景 衰老是一種不可逆轉的自然過程&#xff0c;隨著年齡的增長&#xff0c;機體諸多方面出現功能性下降&#xff0c;與衰老相關的疾病&a…

生成式AI顛覆傳統數據庫的十種方式

對于生成式AI的所有閃光點&#xff0c;這個新時代最大的轉變可能深埋在軟件堆棧中。AI算法正在不易覺察地改變一個又一個數據庫。他們正在用復雜、自適應且看似更直觀的AI新功能顛覆傳統數據庫。 目錄 1、向量和嵌入 2、查詢模型 3、建議 4、索引范例 5、數據分類 6、更…

Unity 框架學習--1

由淺入深&#xff0c;慢慢演化實現框架 兩個類的實現代碼完全一樣&#xff0c;就只有類名或類型不一樣的時候&#xff0c;而且還需要不斷擴展&#xff08;未來會增加各種事件&#xff09;的時候&#xff0c;這時候就用 泛型 繼承 來提取&#xff0c;繼承解決擴展的問題&#…

【RabbitMQ與SpringBoot集成測試收發消息】

【RabbitMQ與SpringBoot集成測試收發消息】 一、環境說明二、實驗步驟三、小結 一、環境說明 安裝環境&#xff1a;虛擬機VMWare Centos7.6 Maven3.6.3 JDK1.8RabbitMQ版本&#xff1a;rabbitmq-server-3.8.8-1.el7.noarch.rpm編程工具Idea 運行JDK為17 二、實驗步驟 在Rab…

List和數組互轉方法以及踩坑點

一、數組轉List 1. 使用for循環逐個添加 String[] arr {"A", "B", "C"}; List<String> list new ArrayList<>(); for (String element : arr) {list.add(element); }2. 使用Arrays.asList(arr) String[] arr {"A", …

TypeScript 泛型的深入解析與基本使用

系列文章目錄 文章目錄 系列文章目錄前言一、泛型的概念二、泛型函數三、泛型類四、泛型接口五、泛型約束總結前言 泛型是TypeScript中的一個重要概念,它允許我們在定義函數、類或接口時使用參數化類型,增強了代碼的靈活性和重用性。本文將深入探討泛型的概念,以及如何在Ty…

智能駕駛系列報告之一:智能駕駛 ChatGPT時刻有望來臨

原創 | 文 BFT機器人 L3 功能加速落地&#xff0c;政策標準有望明確 L2 發展日益成熟&#xff0c;L3 功能加速落地。根據市場監管總局發布的《汽車駕駛自動化分級》與 SAE發布的自動駕駛分級標準&#xff0c;自動駕駛主要分為 6 個級別&#xff08;0 級到 5 級&#xff0c;L0 …

Tomcat多實例部署及nginx+tomcat的負載均衡和動靜分離

Tomcat多實例部署 安裝 jdk、tomcat&#xff08;流程可看之前博客&#xff09; 配置 tomcat 環境變量 [rootlocalhost ~]# vim /etc/profile.d/tomcat.sh#tomcat1 export CATALINA_HOME1/usr/local/tomcat/tomcat1 export CATALINA_BASE1/usr/local/tomcat/tomcat1 export T…

Delphi調用WindowsAPI獲取窗口進程

Delphi有封裝的很好的WindowsAPI&#xff0c;直接調用即可&#xff0c;大體上和C差不多&#xff0c;有些地方需要額外處理。 給出一個實例&#xff1a; varg_process: THandle;procedure initGlobal(); beginvarg_handle: HWND;g_handle : FindWindow(clsName, name);if g_ha…

矩陣定理復習記錄

矩陣復習 矩陣導數定理 若A是一個如下矩陣&#xff1a; A [ a 11 a 12 a 21 a 22 ] A \begin{bmatrix}a_{11}&a_{12}\\a_{21}&a_{22}\end{bmatrix} A[a11?a21??a12?a22??] y是一個向量矩陣&#xff1a; y ? [ y 1 y 2 ] \vec{y}\begin{bmatrix}y_1\\y_2\e…

在vue項目使用數據可視化 echarts ,柱狀圖、折線圖、餅狀圖使用示例詳解及屬性詳解

官網地址&#xff1a;Apache ECharts ?一、下載插件并在頁面中引入 npm install echarts --save 頁面導入&#xff1a; import * as echarts from echarts 全局導入&#xff1a; main.js 中&#xff0c;導入并注冊到全局 import echarts from echarts Vue.prototype.$echart…

Clone函數

概述 Clone函數是一種用于復制的計算機函數。在程序編寫中&#xff0c;除了自定義一個拷貝構造函數來實現對象復制外&#xff0c;還可以實現一個clone函數。這需要借助編譯器實現的一個隱藏拷貝構造函數&#xff0c;這樣的做法&#xff0c;更省心。 中文名clone函數外文名clon…

C# 使用FFmpeg.Autogen對byte[]進行編解碼

C# 使用FFmpeg.Autogen對byte[]進行編解碼&#xff0c;參考&#xff1a;https://github.com/vanjoge/CSharpVideoDemo 入口調用類&#xff1a; using System; using System.IO; using System.Drawing; using System.Runtime.InteropServices; using FFmpeg.AutoGen;namespace F…

C++11異步與通信之 packaged_task

概念簡介 packaged_task 用于包裝可調用目標(Callable)為一個對象,如lambda&#xff0c;普通函數&#xff0c;小括號重載等&#xff0c;用于異步調用。 其返回值或所拋異常被存儲于能通過 std::future 對象訪問的共享狀態中&#xff0c;和promise類似。 將函數的調用與函數返…