為什么會有線程同步的概念呢?為什么要同步?什么是線程同步?先看一段代碼:
package com.maso.test;
public class ThreadTest2 implements Runnable{
private TestObj testObj = new TestObj();
public static void main(String[] args) {
ThreadTest2 tt = new ThreadTest2();
Thread t1 = new Thread(tt, "thread_1");
Thread t2 = new Thread(tt, "thread_2");
t1.start();
t2.start();
}
@Override
public void run() {
for(int j = 0; j < 10; j++){
int i = fix(1);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " : i = " + i);
}
}
public int fix(int y){
return testObj.fix(y);
}
public class TestObj{
int x = 10;
public int fix(int y){
return x = x - y;
}
}
}
輸出結果后,就會發現變量x被兩個線程同一時候操作。這樣就非常easy導致誤操作。
怎樣才干解決問題呢?用線程的同步技術。加上synchronizedkeyword
public synchronized int fix(int y){
return testObj.fix(y);
}加上同步后,就能夠看到有序的從9輸出到-10.
假設加到TestObj類的fix方法上能不能實現同步呢?
public class TestObj{
int x = 10;
public synchronized int fix(int y){
return x = x - y;
}
}假設將synchronized加到方法上則等價於
synchronized(this){
}能夠推斷出兩個線程使用的TestObj類的同一個實例testOjb,所以后實現同步,可是輸出的結果卻不是理想的結果。這是由於當A線程運行完x = x - y后還沒有輸出則B線程已經進入開始運行x = x - y.
所以像以下這樣輸出就不會有什么問題了:
public class TestObj{
public TestObj(){
System.out.println("調用了構造函數");
}
int x = 10;
public synchronized int fix(int y){
x = x - y;
System.out.println(Thread.currentThread().getName() + " : x = " + x);
return x;
}
}假設將外部的fix方法改動例如以下:
public int fix(int y){
ax++ ;
if(ax%2 == 0){
return testObj.fix(y, testObj.str1);
}else{
return testObj.fix(y, testObj.str2);
}
}
public class TestObj{
String str1 = "a1";
String str2 = "a2";
public TestObj(){
System.out.println("調用了構造函數");
}
int x = 10;
public int fix(int y, String str){
synchronized (str) {
x = x - y;
System.out.println(Thread.currentThread().getName() + " : x = " + x);
}
return x;
}
}此時synchronized中的str對象不是同一個對象,所以兩個線程所持有的對象鎖不是同一個,這樣就不能實現同步。
要實現線程之間的相互排斥就要使用同一個對象鎖。
什么是死鎖呢?舉個樣例就是比方你和同學租了個兩室的房子,你拿着你房子的鑰匙。你同學拿着他房子的鑰匙,如今你在房子等你同學將他的鑰匙給你然后你進他房子。你同學在他的房子等你將鑰匙給他然后他進你的房子,這樣就死鎖了。
package com.maso.test;
public class ThreadDieSock implements Runnable {
private int flag = 1;
private Object obj1 = new Object(), obj2 = new Object();
public void run() {
System.out.println("flag=" + flag);
if (flag == 1) {
synchronized (obj1) {
System.out.println("我已經鎖定obj1,歇息0.5秒后鎖定obj2去!");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("1");
}
}
}
if (flag == 0) {
synchronized (obj2) {
System.out.println("我已經鎖定obj2,歇息0.5秒后鎖定obj1去。");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
ThreadDieSock run01 = new ThreadDieSock();
ThreadDieSock run02 = new ThreadDieSock();
run01.flag = 1;
run02.flag = 0;
Thread thread01 = new Thread(run01);
Thread thread02 = new Thread(run02);
System.out.println("線程開始嘍!");
thread01.start();
thread02.start();
}
}
