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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 多线程同步_详解Java多线程编程中的线程同步方法

發布時間:2025/3/12 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 多线程同步_详解Java多线程编程中的线程同步方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、多線程的同步:

1.1、同步機制:在多線程中,可能有多個線程試圖訪問一個有限的資源,必須預防這種情況的發生。所以引入了同步機制:在線程使用一個資源時為其加鎖,這樣其他的線程便不能訪問那個資源了,直到解鎖后才可以訪問。

1.2、共享成員變量的例子:成員變量與局部變量:

成員變量:

如果一個變量是成員變量,那么多個線程對同一個對象的成員變量進行操作,這多個線程是共享一個成員變量的。

局部變量:

如果一個變量是局部變量,那么多個線程對同一個對象進行操作,每個線程都會有一個該局部變量的拷貝。他們之間的局部變量互不影響。

下面舉例說明:

實現了Runnable的線程類:

class MyThread3 implements Runnable{

//兩個線程操作同一個對象,共享成員變量

//int i;

@Override

public void run() {

//兩個線程操作同一個對象,各自保存局部變量的拷貝

int i = 0;

while(i<100){

System.out.println(i);

i++;

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

在main方法中用兩個線程操作同一個對象:

public static void main(String[] args) {

MyThread3 myThread = new MyThread3();

//下面兩個線程對同一個對象(Runnable的實現類對象)進行操作

Thread thread = new Thread(myThread);

Thread thread2 = new Thread(myThread);

//各自保存局部變量的拷貝,互不影響,輸出200個數字

thread.start();

thread2.start();

}

這里如果把i變成成員變量,則輸出100個數字。

1.3、共享資源導致的讀取錯誤下面舉個例子,兩個線程共用一個Number對象,通過Number類的getNumber方法獲取數據,讀取數據并改寫時,發現了重復讀操作:

首先創建一個Number類:

class Number{

private int number = 10;

public String getNumber(int i){

if(number > 0){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

number -= i;

return "取出"+i+"成功,剩余數量:"+number;

}

return "取出"+i+"失敗,剩余數量:"+number;

}

}

線程類,在線程類中的私有屬性包含了Number類的引用:

class MyThread4 extends Thread{

//兩個線程操作同一個對象,共享成員變量

Number number;

public MyThread4(Number number){

this.number = number;

}

@Override

public void run() {

System.out.println(number.getNumber(8));

}

}

在main函數中創建兩個線程類,包含了同一個Number類實例的引用:

public static void main(String[] args) {

Number number = new Number();

//兩個線程操作同一個對象,共享對象number的成員變量number

MyThread4 myThread = new MyThread4(number);

MyThread4 myThread2 = new MyThread4(number);

myThread.start();

myThread2.start();

}

這樣,當第一個線程讀取Number中的number變量時先保存下來再休眠0.1秒,然后第二個線程再讀取number變量并保存,此時兩個線程保存了同樣的數字,在修改時,也就導致修改了同一個數字兩次。

2、同步機制的實現:

在多線程并發編程中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Synchronized進行了各種優化之后,有些情況下它并不那么重了”

Java中的每一個對象都可以作為鎖。

對于同步方法,鎖是當前實例對象。

對于靜態同步方法,鎖是當前對象的Class對象。

對于同步方法塊,鎖是Synchonized括號里配置的對象。

當一個線程試圖訪問同步代碼塊時,它首先必須得到鎖,退出或拋出異常時必須釋放鎖。

2.1、使用synchronized關鍵字創建synchronized方法:使用synchronized關鍵字,該關鍵字修飾的方法叫做同步方法。

Java中每個對象都有一個鎖或者稱為監視器,當訪問某個對象的synchronized方法時,表示將該對象上鎖,而不僅僅是為該方法上鎖。

這樣如果一個對象的synchronized方法被某個線程執行時,其他線程無法訪問該對象的任何synchronized方法(但是可以調用其他非synchronized的方法)。直至該synchronized方法執行完。

靜態的synchronized方法調用情況:

當調用一個對象的靜態synchronized方法時,它鎖定的并不是synchronized方法所在的對象,而是synchronized方法所在對象對應的Class對象。這樣,其他線程就不能調用該類的其他靜態synchronized方法了,但是可以調用非靜態的synchronized方法。

結論:執行靜態synchronized方法鎖方法所在對象,執行非靜態synchronized方法鎖方法所在對象對應的Class對象。

下面是多線程調用靜態的方法的例子,由于鎖定了方法所在對象對應的Class對象,其他線程無法調用該方法所在對象其他的靜態synchronized方法:

/**

* 定義一個類,包含了線程類需要調用的方法

*/

class Compute1{

//這時如果某個線程調用該方法,

//將鎖定synchronized方法所在對象對應的class對象,

//而不是鎖定synchronized方法所在對象

public synchronized static void execute(){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute1 " + i++);

}

}

public synchronized static void execute2(){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute2 " + i++);

}

}

}

main方法中兩個線程分別調用同一個對象的兩個static synchronized方法:

public static void main(String[] args) {

Compute1 com = new Compute1();

Thread thread1 = new Thread1(com);

Thread thread2 = new Thread2(com);

thread1.start();

thread2.start();

}

一次只能調用一個靜態方法,直到執行完成。

2.2、使用synchronized創建同步代碼塊:通過使用synchronized同步代碼塊,鎖定一個對象,該對象作為可執行的標志從而達到同步的效果:

/**

* 定義一個類,包含了線程類需要調用的方法

*/

class Compute1{

//通過同步代碼塊鎖定object1對象進行鎖定了其他同樣的synchronized代碼塊

private Object object1 = new Object();

public void execute(){

synchronized(object1){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute1 " + i++);

}

}

}

public synchronized void execute2(){

synchronized(object1){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute2 " + i++);

}

}

}

}

如果想要使用synchronized同步代碼塊達到和使用synchronized方法同樣的效果,可以鎖定this引用:

synchronized(this){

}

2.3、synchronized方法和synchronized同步代碼塊的區別:synchronized同步代碼塊只是鎖定了該代碼塊,代碼塊外面的代碼還是可以被訪問的。

synchronized方法是粗粒度的并發控制,某一個時刻只能有一個線程執行該synchronized方法。

synchronized同步代碼塊是細粒度的并發控制,只會將塊中的代碼同步,代碼塊之外的代碼可以被其他線程同時訪問。

總結

以上是生活随笔為你收集整理的java 多线程同步_详解Java多线程编程中的线程同步方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。