日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java笔记-多线程中同步加锁相关

發(fā)布時(shí)間:2025/3/15 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java笔记-多线程中同步加锁相关 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Java程序入口就是由JVM啟動(dòng)的main線程:

main線程又可以啟動(dòng)其他線程。當(dāng)所有線程都運(yùn)行結(jié)束時(shí)JVM退出,進(jìn)程結(jié)束。

?

守護(hù)線程(Daemon):守護(hù)線程是為其他線程服務(wù)的線程,所有的非守護(hù)線程都執(zhí)行完畢后,虛擬機(jī)才會退出。

守護(hù)線程的特點(diǎn):不能持有資源(如打開文件等)

?

創(chuàng)建守護(hù)線程:

setDaemon(true);

下面來演示下,子線程中有死循環(huán),而主線程退出了,子線程還沒退出。

程序運(yùn)行截圖如下:

主線程已經(jīng)退出,而子線程沒有退出。

?

源碼如下:

import java.text.SimpleDateFormat; import java.util.Date;class MyThread1 extends Thread{@Overridepublic void run() {while (true) {Date date = new Date(System.currentTimeMillis());SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");System.out.println(formatter.format(date));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} }public class Main1 {public static void main(String[] args) throws InterruptedException {System.out.println("BEGIN");MyThread1 myThread1 = new MyThread1();myThread1.start();Thread.sleep(1000 * 3);System.out.println("OVER");} }

加上守護(hù)線程后,即可在main函數(shù)退出后,頁退出!

程序運(yùn)行截圖如下:

源碼如下:

import java.text.SimpleDateFormat; import java.util.Date;class MyThread1 extends Thread{@Overridepublic void run() {while (true) {Date date = new Date(System.currentTimeMillis());SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");System.out.println(formatter.format(date));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} }public class Main1 {public static void main(String[] args) throws InterruptedException {System.out.println("BEGIN");MyThread1 myThread1 = new MyThread1();myThread1.setDaemon(true);myThread1.start();Thread.sleep(1000 * 3);System.out.println("OVER");} }

下面是線程同步相關(guān)的設(shè)置:

多個(gè)線程同時(shí)運(yùn)行,線程調(diào)度由操作系統(tǒng)決定,程序本身無法決定。

如下多個(gè)線程同時(shí)讀取共享數(shù)據(jù)時(shí):

會出現(xiàn)問題,程序運(yùn)行截圖如下:

代碼如下:

class AddThread extends Thread{@Overridepublic void run() {for(int i = 0; i < Main2.LOOP; i++){Main2.count += 1;}} }class DecThread extends Thread{@Overridepublic void run() {for(int i = 0; i < Main2.LOOP; i++){Main2.count -= 1;}} }public class Main2 {final static int LOOP = 10000;public static int count = 0;public static void main(String[] arg) throws InterruptedException {AddThread addThread = new AddThread();DecThread decThread = new DecThread();addThread.start();decThread.start();addThread.join();decThread.join();System.out.println(count);System.out.println("OVER");} }

對共享數(shù)據(jù)進(jìn)行寫入時(shí),必須要保證是原子操作

Java使用synchronized對一個(gè)對象進(jìn)行加鎖!

synchronized的缺陷:性能會下降;

synchronized的使用:

找出修改共享變量線程代碼塊;選擇一個(gè)實(shí)例作為鎖;使用synchronized(lockObject){...}

運(yùn)行截圖如下:

代碼如下:

class AddThread3 extends Thread{@Overridepublic void run() {for(int i = 0; i < Main2.LOOP; i++){synchronized (Main3.LOCK) {Main2.count += 1;}}} }class DecThread3 extends Thread{@Overridepublic void run() {for(int i = 0; i < Main2.LOOP; i++){synchronized (Main3.LOCK) {Main2.count -= 1;}}} }public class Main3 {final static int LOOP = 10000;public static int count = 0;public static final Object LOCK = new Object();public static void main(String[] arg) throws InterruptedException {AddThread3 addThread = new AddThread3();DecThread3 decThread = new DecThread3();addThread.start();decThread.start();addThread.join();decThread.join();System.out.println(count);System.out.println("OVER");} }

使用synchronized:不用擔(dān)心異常!

public void add(int m){synchronized (obj){if(m < 0){throw new RuntimeException();}this.value += m;}//無論有無異常,都會在此釋放 }

JVM規(guī)范定義了幾種原子操作:

基本類型(long和double除外)賦值:int n = 100;

引用類型的賦值:List<String> list = anotherList;

?

下面是關(guān)于synchronized其他的寫法

public synchronized void add(int n){count += n;total += n; }public void add(int n){synchronized(this){count += n;total += n;} }

上面這兩個(gè)寫法是等價(jià)的。

?

如果一個(gè)類被設(shè)計(jì)為允許多線程正確訪問:這個(gè)類就是“線程安全”的(thread-safe)

如java.lang.StringBuffer就是線程安全的。

?

synchronized是可以重復(fù)使用的。如下:

public void add(int m){synchronized (lockA){this.value += m;synchronized (lockB){this.another += m;}//釋放lockB}//釋放lockA }

這里要注意:不同線程獲取多個(gè)不同對象的鎖可能會導(dǎo)致死鎖。

死鎖形成的條件(注意了,不管是哪個(gè)編程語言都差不多):

兩個(gè)線程各自持有不同的鎖;

兩個(gè)線程各自試圖獲取對方已持有的鎖;

雙方無限等待下去:導(dǎo)致死鎖。

死鎖發(fā)送后:沒有任何機(jī)制能解除死鎖;只能強(qiáng)制結(jié)束JVM進(jìn)程。

如何避免死鎖:線程獲取鎖的順序要一致!

如下實(shí)例!

源碼如下:

class SharedObject{final Object lockA = new Object();final Object lockB = new Object();int accountA = 1000;int accountB = 2000;public void a2b(int balance){synchronized (lockA){accountA -= balance;synchronized (lockB){accountB += balance;}}}public void b2a(int balance){synchronized (lockB){accountB -= balance;synchronized (lockA){accountA += balance;}}} }class AThread extends Thread{@Overridepublic void run() {for(int i = 0; i < Main4.LOOP; i++){Main4.shared.a2b(1);System.out.println("ing...");}} }class BThread extends Thread{@Overridepublic void run() {Main4.shared.b2a(1);for(int i = 0; i < Main4.LOOP; i++){System.out.println("ing...");}} }public class Main4 {final static int LOOP = 100000;static SharedObject shared = new SharedObject();public static void main(String[] args) throws InterruptedException {Thread t1 = new AThread();Thread t2 = new AThread();t1.start();t2.start();t1.join();t2.join();System.out.println("OVER");} }

這個(gè)代碼是有死鎖的但不一定發(fā)送:

原因是這樣的:

此處只要把鎖的先后改成一樣的就可以了!

總結(jié)

以上是生活随笔為你收集整理的Java笔记-多线程中同步加锁相关的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。