主頁 >  其他 > 一文教會你什么執行緒安全以及如何實作執行緒安全

一文教會你什么執行緒安全以及如何實作執行緒安全

2020-12-17 11:10:20 其他


title: 一文教會你什么執行緒安全以及如何實作執行緒安全
tags: 執行緒安全 Java并發 Java記憶體模型 synchronized volatile Lock


文章目錄

      • 一、執行緒安全的概念
      • 二、導致執行緒不安全的原因
      • 三、執行緒安全問題
        • 3.1 原子性
        • 3.2 可見性
        • 3.3 有序性
      • 案例:搶票
      • 四、如何確保執行緒安全?
      • 4.1 synchronized關鍵字
        • 4.1.1 同步代碼塊
        • 4.1.2 同步函式
        • 4.1.3 多執行緒死鎖執行緒
      • 4.2 Lock
      • 4.3 volatile關鍵字
      • 解決辦法:
      • 4.4 synchronized、volatile和Lock之間的區別

一、執行緒安全的概念

執行緒安全是多執行緒編程是的計算機程式代碼中的一個概念,在擁有共享資料的多條執行緒并行執行的程式中,執行緒安全的代碼會通過同步機制保證各個執行緒都可以正常且準確的執行,不會出現資料污染等意外情況,上述是百度百科給出的一個概念解釋,換言之,執行緒安全就是某個函式在并發環境中呼叫時,能夠處理好多個執行緒之間的共享變數,是程式能夠正確執行完畢,也就是說我們想要確保在多執行緒訪問的時候,我們的程式還能夠按照我們的預期的行為去執行,那么就是執行緒安全了,

二、導致執行緒不安全的原因

首先,可以來看一段代碼,來看看是不是執行緒安全的,代碼如下:

package com.company;

public class TestThread {

    private static class XRunnable implements Runnable{
        private int count;
        public void run(){
            for(int i= 0; i<5; i++){
                getCount();
            }
        }

        public void getCount(){
            count++;
            System.out.println(" "+count);
        }
    }

    public static void main(String[] args) {
        XRunnable runnable = new XRunnable();
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);
        t1.start();
        t2.start();
        t3.start();
    }
}

輸出的結果為:

 2
 3
 2
 5
 4
 7
 6
 10
 11
 12
 9
 8
 13
 14
 15

從代碼上進行分析,當啟動了三個執行緒,每個執行緒應該都是回圈5次得出1到15的結果,但是從輸出的結果,就可以看到有兩個2輸出,出現像這種情況表明這個方法根本就不是執行緒安全的,我們可以這樣理解:在每個行程的記憶體空間中都會有一塊特殊的公共區域,通常稱為堆(記憶體),之所以會輸出兩個2,是因為行程內的所有執行緒都可以訪問到該區域,當第一個執行緒已經獲得2這個數了,還沒來得及輸出,下一個執行緒在這段時間的空隙獲得了2這個值,故輸出時會輸出2的值,

三、執行緒安全問題

要考慮執行緒安全問題,就需要先考慮Java并發的三大基本特性原子性可見性以及有序性

3.1 原子性

原子性是指在一個操作中就是cpu不可以在中途暫停然后再調度,即不被中斷操作,要不全部執行完成,要不都不執行,就好比轉賬,從賬戶A向賬戶B轉1000元,那么必然包括2個操作:從賬戶A減去1000元,往賬戶B加上1000元,2個操作必須全部完成,

那程式中原子性指的是最小的操作單元,比如自增操作,它本身其實并不是原子性操作,分了3步的,包括讀取變數的原始值、進行加1操作、寫入作業記憶體,所以在多執行緒中,有可能一個執行緒還沒自增完,可能才執行到第二部,另一個執行緒就已經讀取了值,導致結果錯誤,那如果我們能保證自增操作是一個原子性的操作,那么就能保證其他執行緒讀取到的一定是自增后的資料,

3.2 可見性

當多個執行緒訪問同一個變數時,一個執行緒修改了這個變數的值,其他執行緒能夠立即看得到修改的值,

若兩個執行緒在不同的cpu,那么執行緒1改變了i的值還沒重繪到主存,執行緒2又使用了i,那么這個i值肯定還是之前的,執行緒1對變數的修改執行緒沒看到這就是可見性問題,

3.3 有序性

程式執行的順序按照代碼的先后順序執行,在多執行緒編程時就得考慮這個問題,

案例:搶票

當多個執行緒同時共享,同一個全域變數或靜態變數(即區域變數不會),做寫的操作時,可能會發生資料沖突問題,也就是執行緒安全問題,但是做讀操作是不會發生資料沖突問題,

Consumer類:

package com.company;

public class Consumer implements Runnable{

    private int ticket = 100;

    public void run(){
        while(ticket>0){
            System.out.println(Thread.currentThread().getName() + "售賣第" + (100-ticket+1) + "張票");
            ticket--;
        }
    }

}

主類:

package com.company;

public class ThreadSafeProblem {
    public static void main(String[] args){
        Consumer abc = new Consumer();

        new Thread(abc, "視窗1").start();
        new Thread(abc, "視窗2").start();
    }
}

結果:

從輸出結果來看,售票視窗買票出現了計票的問題,這就是執行緒安全出現問題了,

四、如何確保執行緒安全?

解決辦法:使用多執行緒之間使用關鍵字synchronized、或者使用鎖(lock),或者volatile關鍵字

①synchronized(自動鎖,鎖的創建和釋放都是自動的);

②lock 手動鎖(手動指定鎖的創建和釋放),

③volatile關鍵字

為什么能解決?如果可能會發生資料沖突問題(執行緒不安全問題),只能讓當前一個執行緒進行執行,代碼執行完成后釋放鎖,然后才能讓其他執行緒進行執行,這樣的話就可以解決執行緒不安全問題,

4.1 synchronized關鍵字

4.1.1 同步代碼塊

synchronized(同一個鎖){
  //可能會發生執行緒沖突問題
}

將可能會發生執行緒安全問題地代碼,給包括起來,也稱為同步代碼塊synchronized使用的鎖可以是物件鎖也可以是靜態資源,如×××.class,只有持有鎖的執行緒才能執行同步代碼塊中的代碼,沒持有鎖的執行緒即使獲取cpu的執行權,也進不去,

鎖的釋放是在synchronized同步代碼執行完畢后自動釋放,

同步的前提:

1,必須要有兩個或者兩個以上的執行緒 ,如果小于2個執行緒,則沒有用,且還會消耗性能(獲取鎖,釋放鎖)

2,必須是多個執行緒使用同一個鎖

弊端:多個執行緒需要判斷鎖,較為消耗資源、搶鎖的資源,

例子:

public class ThreadSafeProblem {
    public static void main(String[] args) {
        Consumer abc = new Consumer();
        // 注意要使用同一個abc變數作為thread的引數,
        // 如果你使用了兩個Consumer物件,那么就不會共享ticket了,就自然不會出現執行緒安全問題
        new Thread(abc,"視窗1").start();
        new Thread(abc,"視窗2").start();
    }
}
class Consumer implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (ticket > 0) {
            synchronized (Consumer.class) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "售賣第" + (100-ticket+1) + "張票");
                    ticket--;
                }
            }
        }
    }
}

4.1.2 同步函式

就是將synchronized加在方法上,

分為兩種:

第一種是非靜態同步函式,即方法是非靜態的,使用的this物件鎖,如下代碼所示

第二種是靜態同步函式,即方法是用static修飾的,使用的鎖是當前類的class檔案(xxx.class)

public synchronized void sale () {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "售賣第" + (100-ticket+1) + "張票");
            ticket--;
        }
    }

4.1.3 多執行緒死鎖執行緒

如下代碼所示,

執行緒t1,運行后在同步代碼塊中需要oj物件鎖,,運行到sale方法時需要this物件鎖

執行緒t2,運行后需要呼叫sale方法,需要先獲取this鎖,再獲取oj物件鎖

那這樣就會造成,兩個執行緒相互等待對方釋放鎖,就造成了死鎖情況,簡單來說就是:

同步中嵌套同步,導致鎖無法釋放,

class ThreadTrain3 implements Runnable {
	private static int count = 100;
	public boolean flag = true;
	private static Object oj = new Object();
	@Override
	public void run() {
		if (flag) {
			while (true) {
				synchronized (oj) {
					sale();
				}
			}
 
		} else {
			while (true) {
				sale();
			}
		}
	}
 
	public static synchronized void sale() {
		// 前提 多執行緒進行使用、多個執行緒只能拿到一把鎖,
		// 保證只能讓一個執行緒 在執行 缺點效率降低
		synchronized (oj) {
			if (count > 0) {
				try {
					Thread.sleep(50);
				} catch (Exception e) {
					// TODO: handle exception
				}
				System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - count + 1) + "票");
				count--;
			}
		}
	}
}
 
public class ThreadDemo3 {
	public static void main(String[] args) throws InterruptedException {
		ThreadTrain3 threadTrain1 = new ThreadTrain3();
		Thread t1 = new Thread(threadTrain1, "①號視窗");
		Thread t2 = new Thread(threadTrain1, "②號視窗");
		t1.start();
		Thread.sleep(40);
		threadTrain1.flag = false;
		t2.start();
	}
}

4.2 Lock

可以視為synchronized的增強版,提供了更靈活的功能,該介面提供了限時鎖等待、鎖中斷、鎖嘗試等功能,synchronized實作的同步代碼塊,它的鎖是自動加的,且當執行完同步代碼塊或者拋出例外后,鎖的釋放也是自動的,

 Lock l = ...;
 l.lock();
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock();
 }

但是Lock鎖是需要手動去加鎖和釋放鎖,所以Lock相比于synchronized更加的靈活,且還提供了更多的功能比如說

tryLock()方法會嘗試獲取鎖,如果鎖不可用則回傳false,如果鎖是可以使用的,那么就直接獲取鎖且回傳true,官方代碼如下:

Lock lock = ...;
 if (lock.tryLock()) {
   try {
     // manipulate protected state
   } finally {
     lock.unlock();
   }
 } else {
   // perform alternative actions
 }

例子:

/*
 * 使用ReentrantLock類實作同步
 * */
class MyReenrantLock implements Runnable{
	//向上轉型
	private Lock lock = new ReentrantLock();
	public void run() {
		//上鎖
		lock.lock();
		for(int i = 0; i < 5; i++) {
			System.out.println("當前執行緒名: "+ Thread.currentThread().getName()+" ,i = "+i);
		}
		//釋放鎖
		lock.unlock();
	}
}
public class MyLock {
	public static void main(String[] args) {
		MyReenrantLock myReenrantLock =  new MyReenrantLock();
		Thread thread1 = new Thread(myReenrantLock);
		Thread thread2 = new Thread(myReenrantLock);
		Thread thread3 = new Thread(myReenrantLock);
		thread1.start();
		thread2.start();
		thread3.start();
	}
}

輸出結果:

由此我們可以看出,只有當當前執行緒列印完畢后,其他的執行緒才可繼續列印,執行緒列印的資料是分組列印,因為當前執行緒持有鎖,但執行緒之間的列印順序是隨機的,

即呼叫lock.lock() 代碼的執行緒就持有了“物件監視器”,其他執行緒只有等待鎖被釋放再次爭搶,

4.3 volatile關鍵字

先來看一段錯誤的代碼示例:

class ThreadVolatileDemo extends Thread {
	public boolean flag = true;
 
	@Override
	public void run() {
		System.out.println("子執行緒開始執行");
		while (flag) {
		}
		System.out.println("子執行緒執行結束...");
	}
	public void setFlag(boolean flag){
		this.flag=flag;
	}
 
}
 
public class ThreadVolatile {
	public static void main(String[] args) throws InterruptedException {
              ThreadVolatileDemo threadVolatileDemo = new ThreadVolatileDemo();
              threadVolatileDemo.start();
              Thread.sleep(3000);
              threadVolatileDemo.setFlag(false);
              System.out.println("flag已被修改為false!");
	}
}

輸出結果:

雖然flag已被修改,但是子執行緒依然在執行,這里產生的原因就是Java記憶體模型(JMM) 導致的,

由于主執行緒休眠了3秒,所以子執行緒沒有意外的話是一定會被執行run方法的,而當子執行緒由于呼叫start方法而執行run方法時,會將flag這個共享變數拷貝一份副本存到執行緒的本地記憶體中,此時執行緒中的flag為true,即使主執行緒在休眠后修改了flag值為false,子執行緒也不會知道,即不會修改自己副本的flag值,所以這就導致了該問題的出現,

? 注意:在測驗時,一定要讓主執行緒進行sleep或其他耗時操作,如果沒有這步操作,很有可能在子執行緒執行run方法而拷貝共享變數到執行緒本地記憶體之前,主執行緒就已經修改了flag值,

這里再來介紹一下Java記憶體模型吧!!!

Java記憶體模型規定了所有的變數(這里的變數是指成員變數,靜態欄位等但是不包括區域變數和方法引數,因為這是執行緒私有的)都存盤在主記憶體中,每條執行緒還有自己的作業記憶體,執行緒的作業記憶體中拷貝了該執行緒使用到的主記憶體中的變數(只是副本,從主記憶體中拷貝了一份,放到了執行緒的本地記憶體中),執行緒對變數的所有操作都必須在作業記憶體中進行,而不能直接讀寫主記憶體, 不同的執行緒之間也無法直接訪問對方作業記憶體中的變數,執行緒間變數的傳遞均需要自己的作業記憶體和主存之間進行資料同步進行

而JMM就作用于作業記憶體和主存之間資料同步程序,他規定了如何做資料同步以及什么時候做資料同步,

1. 首先要將共享變數從主記憶體拷貝到執行緒自己的作業記憶體空間,作業記憶體中存盤著主記憶體中的變數副本拷貝;

2. 執行緒對副本變數進行操作,(不能直接操作主記憶體);

3. 操作完成后通過JMM 將執行緒的共享變數副本與主記憶體進行資料的同步,將資料寫入主記憶體中;

4. 不同的執行緒間無法訪問對方的作業記憶體,執行緒間的通信(傳值)必須通過主記憶體來完成,

當多個執行緒同時訪問一個資料的時候,可能本地記憶體沒有及時重繪到主記憶體,所以就會發生執行緒安全問題

JMM是在執行緒調run方法的時候才將共享變數寫到自己的執行緒本地記憶體中去的,而不是在呼叫start方法的時候,

解決辦法:

當出現這種問題時,就可以使用Volatile關鍵字進行解決,

Volatile 關鍵字的作用是變數在多個執行緒之間可見,使用Volatile關鍵字將解決執行緒之間可見性,強制執行緒每次讀取該值的時候都去“主記憶體”中取值

只需要在flag屬性上加上該關鍵字即可,

public volatile boolean flag = true;

子執行緒每次都不是讀取的執行緒本地記憶體中的副本變數了,而是直接讀取主記憶體中的屬性值,

volatile雖然具備可見性,但是不具備原子性

4.4 synchronized、volatile和Lock之間的區別


synochronizd和volatile關鍵字區別:

1)volatile關鍵字解決的是變數在多個執行緒之間的可見性;而sychronized關鍵字解決的是多個執行緒之間訪問共享資源的同步性,

tip: final關鍵字也能實作可見性:被final修飾的欄位在構造器中一旦初始化完成,并且構造器沒有把 “this” 的參考傳遞出去(this參考逃逸是一件很危險的事情,其它執行緒有可能通過這個參考訪問到了"初始化一半"的物件),那在其他執行緒中就能看見final;

2)volatile只能用于修飾變數,而synchronized可以修飾方法,以及代碼塊,(volatile是執行緒同步的輕量級實作,所以volatile性能比synchronized要好,并且隨著JDK新版本的發布,sychronized關鍵字在執行上得到很大的提升,在開發中使用synchronized關鍵字的比率還是比較大);

3)多執行緒訪問volatile不會發生阻塞,而sychronized會出現阻塞;

4)volatile能保證變數在多個執行緒之間的可見性,但不能保證原子性;而sychronized可以保證原子性,也可以間接保證可見性,因為它會將私有記憶體和公有記憶體中的資料做同步,

執行緒安全包含原子性可見性兩個方面,

對于用volatile修飾的變數,JVM虛擬機只是保證從主記憶體加載到執行緒作業記憶體的值是最新的,

一句話說明volatile的作用:實作變數在多個執行緒之間的可見性,


synchronized和lock區別:

1)Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內置的語言實作;

2)synchronized在發生例外時,會自動釋放執行緒占有的鎖,因此不會導致死鎖現象發生;而Lock在發生例外時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

3)Lock可以讓等待鎖的執行緒回應中斷,而synchronized卻不行,使用synchronized時,等待的執行緒會一直等待下去,不能夠回應中斷;

4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到,

5)Lock可以提高多個執行緒進行讀操作的效率(讀寫鎖),

在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量執行緒同時競爭),此時Lock的性能要遠遠優于synchronized,所以說,在具體使用時要根據適當情況選擇,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/236029.html

標籤:其他

上一篇:如何使用html5在現代瀏覽器中使用VLC播放RTSP流

下一篇:ConcurrentHashMap原始碼分析(JDK1.7)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more