synchronized詳解

基於synchronized本身寫了一個小demo作實驗,起兩個線程調用一個方法,這個方法在單線程運行下能夠把變量增長10000html

 

如代碼寫了4種synchronized方式java

a:在方法上,控制方法的訪問安全

b:在對象上,控制對象的訪問併發

c:在修改的包裝類ia上,預期控制ia的修改ui

d:在對象sint上,控制stest對象的訪問this

d:在對象sint上,控制stest對象的訪問atom

e:沒有使用synchronized,而是使用atomicInteger變量作增長線程

f:在Sint的class上,code

 

成功達到預期的組合有 aa,bb,dd,ee,abhtm

首先看兩個線程調用一個同一個方法預期與結果不通的,只有c方法,c和d方法不一樣在於,d是synchronized了一個普通對象,c是synchronized了一個包裝類,發現包裝類沒有+1相似的方法,應該和包裝類底層相關,留做問題

不一樣的方法組合只有ab,dd1能夠,由於ab臨界資源能夠說有重合,若是a先執行,線程ta獲取了sTest的鎖,b就獲取sTest的鎖失敗,只有等a執行結束,反之同理

d和d1都是都要獲取sint對象鎖,鎖是臨界資源,ta,tb線程誰先獲取了sint對象鎖執行完成,第二個線程才能執行


stest和stest1併發執行d時,輸出不是預期的,由於sint是在stest內生成的,tatb線程鎖住的不一樣對象,併發互不干擾的執行

synchronized對象時,必須是同一個對象的鎖,加上

Sint sint = new Sint();
sTest.sint = sint;
sTest1.sint = sint
這段代碼,stest和stest1併發執行後結果是預期的,由於同一時間只有一個線程能夠獲取到sint的鎖



Sint sint = new Sint();
sTest.sint = sint;
sTest1.sint = sint

stest和stest1併發執行f方法時,結果就是預期的
stest執行f,stest1執行d,結果不是預期的,兩個線程獲取的鎖不一樣,互不干擾的併發執行


如下是來自博客http://www.cnblogs.com/highriver/archive/2011/12/18/2291965.html

synchronized(class)很特別,它會讓另外一個線程在任何須要獲取class作爲monitor的地方等待.class與this作爲不一樣的監視器能夠同時使用,不存在一個線程獲取了class,另外一個線程就不能獲取該class的一切實例.

synchronized(class)
synchronized(this)
->線程各自獲取monitor,不會有等待.
synchronized(this)
synchronized(this)
->若是不一樣線程監視同一個實例對象,就會等待,若是不一樣的實例,不會等待.
synchronized(class)
synchronized(class)
->若是不一樣線程監視同一個實例或者不一樣的實例對象,都會等待.
 
 
package test.synchronize_wait_notify_lock.synchronizedp;

import java.util.concurrent.atomic.AtomicInteger;

/**
* @Auther: zhangyahui
* @Date: 2019/1/31 15:41
* @Description:
*/
public class SynchronizedTest {

public static void main(String[] args) throws InterruptedException {

STest sTest = new STest();

STest sTest1 = new STest();


new Thread() {
public void run() {
sTest.d("ta");
}

;
}.start();

new Thread() {
public void run() {
sTest.d1("tb");
}

;
}.start();


/*Sint sint = new Sint();
sTest.sint = sint;
sTest1.sint = sint;

new Thread() {
public void run() {
sTest.d("ta");
}

;
}.start();

new Thread() {
public void run() {
sTest1.d1("tb1");
}

;
}.start();*/

}
}

class Sint {
private int i = 0;
private int m = 0;

public int getI() {
return i;
}

public void setI(int i) {
this.i = i;
}

public int getM() {
return m;
}

public void setM(int m) {
this.m = m;
}
}

class STest {
static Integer ia = 0;
AtomicInteger ai = new AtomicInteger(0);
static final int count = 10000;
Sint sint = new Sint();


public synchronized void a(String s) {
/*synchronized(ia)*/
{
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
i++;
}
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}

public void b(String s) {
synchronized (this) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* c方法沒有預期的效果,結果很亂,應該是包裝類自己的問題
* 最後的結果也大機率不是20000
*/
public void c(String s) {
synchronized (ia) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* d方法的輸出和預期一致,鎖住了sint對象的操做
*/
public void d(String s) {
synchronized (sint) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
sint.setI(ia);
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* d方法的輸出和預期一致,鎖住了sint對象的操做
*/
public void d1(String s) {
synchronized (sint) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
sint.setM(ia);
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* 使用了原子int,先結束的線程值大機率不是10000而是一個接近20000的數字
* 可是最後結束的線程輸出的值必然是20000,原子int自身維護了資源的訪問
*/
public void e(String s) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ai.incrementAndGet();
i++;
}
System.out.println("this is " + s + " " + ai.get() + " " + System.currentTimeMillis());
}
}

public void f(String s) {
synchronized (Sint.class) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
sint.setM(ia);
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

 

 

 

 

 

一個線程獲取了對象的鎖之後,能夠訪問該對象全部的synchronized方法或方法塊

如下是來自海子博客的一些內容https://www.cnblogs.com/dolphin0520/p/3923737.html

 

synchronized方法。

  1)當一個線程正在訪問一個對象的synchronized方法,那麼其餘線程不能訪問該對象的其餘synchronized方法。這個緣由很簡單,由於一個對象只有一把鎖,當一個線程獲取了該對象的鎖以後,其餘線程沒法獲取該對象的鎖,因此沒法訪問該對象的其餘synchronized方法。

  2)當一個線程正在訪問一個對象的synchronized方法,那麼其餘線程能訪問該對象的非synchronized方法。這個緣由很簡單,訪問非synchronized方法不須要得到該對象的鎖,假如一個方法沒用synchronized關鍵字修飾,說明它不會使用到臨界資源,那麼其餘線程是能夠訪問這個方法的,

  3)若是一個線程A須要訪問對象object1的synchronized方法fun1,另一個線程B須要訪問對象object2的synchronized方法fun1,即便object1和object2是同一類型),也不會產生線程安全問題,由於他們訪問的是不一樣的對象,因此不存在互斥問題。

相關文章
相關標籤/搜索