Java多執行緒學習筆記(一) synchronized同步方法
阿新 • • 發佈:2018-11-08
synchronized同步方法
- 1.提出問題-例項變數非執行緒安全
- 2. 解決問題-給方法上加synchronized
- 3.思考問題-如果是多個物件的鎖
- 4.思考問題-非synchronized方法會鎖著嗎
1.提出問題-例項變數非執行緒安全
如果多個執行緒同時訪問1個物件的例項變數,則可能出現"非執行緒安全"問題。
1.1 何為非執行緒安全?
我的理解是多個執行緒對一個例項變數操作會出現值被更改,不同步的情況。
1.2 舉例
1.2.1 有私有變數的類HasPrivateNum (供多執行緒們去呼叫)
public class HasPrivateNum {
private int num = 0;
public void addNum(String userName){
try{
if (userName.equalsIgnoreCase("wang.dong")){
num = 1;
System.out.println("wang dong set over");
Thread. sleep(2000);
}else {
num = 2;
System.out.println("other man set over");
}
System.out.println(userName + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
這個類裡面有一個私有變數 num,在addNum()函式里根據傳的userName不同而賦值.
1.2.2 執行緒A
public class ThreadA extends Thread{
private HasPrivateNum num;
public ThreadA(HasPrivateNum num){
super();
this.num = num;
}
@Override
public void run(){
super.run();
num.addNum("wang.dong");
}
}
1.2.3 執行緒B
public class ThreadB extends Thread{
private HasPrivateNum num;
public ThreadB(HasPrivateNum num){
super();
this.num = num;
}
@Override
public void run(){
super.run();
num.addNum("other man");
}
}
1.2.4 開啟AB執行緒共同訪問1個物件
public class Run {
public static void main(String[] args) {
HasPrivateNum numRef = new HasPrivateNum();
//A
ThreadA aThread = new ThreadA(numRef);
aThread.start();
//B
ThreadB bThread = new ThreadB(numRef);
bThread.start();
}
}
1.2.5 執行結果(多次執行有機率出現如下結果)
A和B這2個執行緒同時訪問一個沒有同步的方法,並給裡面變數賦值,可能出現"非執行緒安全"問題
2. 解決問題-給方法上加synchronized
2.1 synchronized修飾範圍
修飾物件 | 作用範圍 | 作用物件 |
---|---|---|
程式碼塊 | synchronized(this){}內 | 呼叫這個程式碼塊的物件 |
方法(介面方法/構造方法不行) | 整個方法 | 呼叫這個方法的例項物件 |
靜態方法 | 整個方法 | 這個類的所有類物件(共用一把鎖) |
類 | synchronized後面{} | 這個類的所有物件(共用一把鎖) |
2.2 修改後的HasPrivateNum類
public class HasPrivateNum {
private int num = 0;
// add synchroized
public synchronized void addNum(String userName){
try{
if (userName.equalsIgnoreCase("wang.dong")){
num = 1;
System.out.println("wang dong set over");
Thread.sleep(2000);
}else {
num = 2;
System.out.println("other man set over");
}
System.out.println(userName + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
2.3 執行結果(多次執行一定是這樣)
如圖說明執行緒B是等待執行緒A執行完畢後並釋放了鎖,才能獲取鎖
3.思考問題-如果是多個物件的鎖
在上面1.2.4裡只定義了一個HasPrivateNum的物件,如果有個HasPrivateNum物件,AB執行緒範圍不同的物件,會是同步還是非同步呢?
3.1 修改Run類
public class RunTwo {
public static void main(String[] args) {
HasPrivateNum numRef_1 = new HasPrivateNum();
HasPrivateNum numRef_2 = new HasPrivateNum();
//A
ThreadA aThread = new ThreadA(numRef_1);
aThread.start();
//B
ThreadB bThread = new ThreadB(numRef_2);
bThread.start();
}
}
A執行緒和B執行緒分別用不同的物件
3.2 執行結果
因為A執行緒睡了2秒,說是後列印的,這個2個執行緒是非同步執行的,不相互影響
這個結果說明關鍵字synchronized的鎖是物件鎖,不是把一段程式碼或函式鎖住
4.思考問題-非synchronized方法會鎖著嗎
一個物件有synchronized方法和非synchronized方法,如果執行緒A佔用了synchronized方法,執行緒B是否可以訪問這個物件的非synchronized方法?
4.1修改HasPrivateNum類
public class HasPrivateNum {
private int num = 0;
// add synchroized
public synchronized void addNum(String userName){
try{
if (userName.equalsIgnoreCase("wang.dong")){
num = 1;
System.out.println("wang dong set over");
Thread.sleep(2000);
}else {
num = 2;
System.out.println("other man set over");
}
System.out.println(userName + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
// not synchronized
public void anotherMethod(){
try{
System.out.println(Thread.currentThread().getName() + " anotherMethod begin");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " anotherMethod end");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
4.2修改執行緒B呼叫非synchronized方法
public class ThreadB extends Thread{
private HasPrivateNum num;
public ThreadB(HasPrivateNum num){
super();
this.num = num;
}
@Override
public void run(){
super.run();
//num.addNum("other man");
num.anotherMethod();
}
}
4.3 run方法
public class Run {
public static void main(String[] args) {
HasPrivateNum numRef = new HasPrivateNum();
//A
ThreadA aThread = new ThreadA(numRef);
aThread.start();
//B
ThreadB bThread = new ThreadB(numRef);
bThread.start();
}
}
4.4 執行結果
從結果看出執行緒A和執行緒B是非同步執行的
- 多個執行緒同時訪問同一個object的synchronized(this)程式碼塊時,一個時間只有一個執行緒,其他執行緒只能等待
- 其他執行緒可以訪問該object的非synchronized(this)程式碼塊
這次暫時寫這麼多吧,加油!