利用synchronized關鍵字是最簡單的實現同步的方式,synchronized可以用於方法,代碼塊,synchronized可以保證在同一時刻,只有一個線程可以執行某個方法或某個代碼塊,同時synchronized可以保證一個線程的變化可見。也就是保證了臨界區某一時刻只能被一個線程訪問(被synchronized修飾的方法,或者代碼塊都是臨界區)。當一個線程進入了臨界區,其他試圖訪問該臨界區的線程將會被掛起,知道第一個線程執行完正在運行的方法。
synchronized的使用:
- 普通方法,鎖是當前對象的實例
- 靜態方法,鎖是當前類的class對象
- 同步方法塊,鎖是括號裏面的對象。
注意:
對於靜態同步方法存在這樣一種情況,因爲鎖是當前類的class對象,所以同一時間只能有一個線程訪問,但是對於其他的普通方法,其他線程也是可以訪問修改的,如果其他方法中對臨界區中的數據進行了修改,也會造成數據的不一致。
代碼示例講解,最簡單的例子是對一個數進行加減法。
普通方法
// add del 方法都是臨界區
public class Demo8 {
public static void main(String[] args) {
long number = 100;
NumberData numberData = new NumberData(number);
Thread thread1 = new Thread(new User(numberData, 10));
Thread thread2 = new Thread(new User(numberData, -50));
Thread thread3 = new Thread(new User(numberData, 10));
Thread thread4 = new Thread(new User(numberData, -10));
Thread thread5 = new Thread(new User(numberData, -40));
Thread thread6 = new Thread(new User(numberData, 10));
Thread thread7 = new Thread(new User(numberData, -10));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
}
static class NumberData implements Serializable{
private long number;
public NumberData(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public synchronized void add(long num) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======add============ "+num+" "+number);
}
public synchronized void del(long num) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======del============ "+num+" "+number);
}
}
static class User implements Runnable{
private NumberData numberData;
private long number;
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public NumberData getNumberData() {
return numberData;
}
public void setNumberData(NumberData numberData) {
this.numberData = numberData;
}
public User(NumberData numberData,long num) {
super();
this.numberData = numberData;
this.number = num;
}
@Override
public void run() {
if (number > 0) {
numberData.add(number);
}else {
numberData.del(number);
}
}
}
}
同步代碼塊:
public class Demo8 {
public static void main(String[] args) {
long number = 100;
NumberData numberData = new NumberData(number);
Thread thread1 = new Thread(new User(numberData, 10));
Thread thread2 = new Thread(new User(numberData, -50));
Thread thread3 = new Thread(new User(numberData, 10));
Thread thread4 = new Thread(new User(numberData, -10));
Thread thread5 = new Thread(new User(numberData, -40));
Thread thread6 = new Thread(new User(numberData, 10));
Thread thread7 = new Thread(new User(numberData, -10));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
}
static class NumberData implements Serializable{
private long number;
public NumberData(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public void add(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======add============ "+num+" "+number);
}
}
public void del(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======del============ "+num+" "+number);
}
}
}
static class User implements Runnable{
private NumberData numberData;
private long number;
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public NumberData getNumberData() {
return numberData;
}
public void setNumberData(NumberData numberData) {
this.numberData = numberData;
}
public User(NumberData numberData,long num) {
super();
this.numberData = numberData;
this.number = num;
}
@Override
public void run() {
if (number > 0) {
numberData.add(number);
}else {
numberData.del(number);
}
}
}
}
或者設置一個公共的對象,作爲統一的一個鎖。
靜態同步方法:
public class Demo9 {
public static void main(String[] args) {
long number = 100;
NumberData numberData = new NumberData(number);
Thread thread1 = new Thread(new User(numberData, 10));
Thread thread2 = new Thread(new User(numberData, -50));
Thread thread3 = new Thread(new User(numberData, 10));
Thread thread4 = new Thread(new User(numberData, -10));
Thread thread5 = new Thread(new User(numberData, -40));
Thread thread6 = new Thread(new User(numberData, 10));
Thread thread7 = new Thread(new User(numberData, -10));
Thread thread8 = new Thread() {
@Override
public void run() {
NumberData.staticFun1();
}
};
Thread thread9 = new Thread() {
@Override
public void run() {
NumberData.staticFun2();
}
};
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
}
static class NumberData implements Serializable{
private long number;
public NumberData(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public void add(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======add============ "+num+" "+number);
}
}
public void del(long num) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number = number + num;
System.out.println("=======del============ "+num+" "+number);
}
}
public static synchronized void staticFun1() {
for(int i=0;i<4;i++) {
try {
Thread.sleep(500);
System.out.println("========staticFun1========");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static synchronized void staticFun2() {
for(int i=0;i<4;i++) {
try {
Thread.sleep(500);
System.out.println("========staticFun2========");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class User implements Runnable{
private NumberData numberData;
private long number;
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
public NumberData getNumberData() {
return numberData;
}
public void setNumberData(NumberData numberData) {
this.numberData = numberData;
}
public User(NumberData numberData,long num) {
super();
this.numberData = numberData;
this.number = num;
}
@Override
public void run() {
if (number > 0) {
numberData.add(number);
}else {
numberData.del(number);
}
}
}
}
result:
=======add============ 10 110
=======del============ -10 100
=======add============ 10 110
=======del============ -40 70
========staticFun1========
=======del============ -10 60
=======add============ 10 70
=======del============ -50 20
========staticFun1========
========staticFun1========
========staticFun1========
========staticFun2========
========staticFun2========
========staticFun2========
========staticFun2========
對於static方法synchronized鎖的對象是當前類的class對象,所以和普通的synchronized方法不存在互斥問題,可以同時執行,但對於同步static方法,同時只能有一個執行。