線(xiàn)程的同步是為了防止多個(gè)線(xiàn)程訪問(wèn)一個(gè)數(shù)據(jù)對(duì)象時(shí),對(duì)數(shù)據(jù)造成的破壞。同步的方法通過(guò)鎖來(lái)實(shí)現(xiàn),每個(gè)對(duì)象都有且僅有一個(gè)鎖,這個(gè)鎖與一個(gè)特定的對(duì)象關(guān)聯(lián),線(xiàn)程一旦獲取了對(duì)象鎖,其他訪問(wèn)該對(duì)象的線(xiàn)程就無(wú)法再訪問(wèn)該對(duì)象的其他同步方法。
對(duì)于同步的方法,這里先主要學(xué)習(xí)使用synchronized關(guān)鍵字修飾的方法和鎖對(duì)象Lock
1、 Synchronized
Java中每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖,當(dāng)程序運(yùn)行到非靜態(tài)的synchronized同步方法上時(shí),自動(dòng)獲得與正在執(zhí)行代碼類(lèi)的當(dāng)前實(shí)例(this實(shí)例)有關(guān)的鎖,也只有在這時(shí),對(duì)象鎖才起作用。一個(gè)對(duì)象只有一個(gè)鎖。如果一個(gè)線(xiàn)程獲得該鎖,就沒(méi)有其他線(xiàn)程可以獲得鎖,直到第一個(gè)線(xiàn)程釋放(或返回)鎖。也就是說(shuō)任何其他線(xiàn)程都不能進(jìn)入該對(duì)象上的synchronized方法或代碼塊,直到持鎖線(xiàn)程退出了synchronized同步方法或代碼塊該鎖被釋放。(同步只能是同步方法,變量和類(lèi)不能同步)
package Synchronized20170412;
/**
* 線(xiàn)程同步的運(yùn)用
*/
public class Synchronized20170412 {
public static void main(String[] args) {
Fun f = new Fun();
NewThread new_thread = new NewThread(f);
Thread thread1 = new Thread(new_thread);
thread1.start();
Thread thread2 = new Thread(new_thread);
thread2.start();
}
}
class Fun {
private int total = 0;
public int getTotal() {
return total;
}
/**
* 用同步方法實(shí)現(xiàn)
*
* @param money
*/
public synchronized void add(int i) {
total += i;
}
/**
* 用同步代碼塊實(shí)現(xiàn)
*
* @param money
*/
public void add1(int i) {
synchronized (this) {
total += i;
}
}
}
class NewThread implements Runnable {
private Fun f;
public NewThread(Fun f) {
this.f = f;
}
public void run() {
//System.out.println(Thread.currentThread().getName() + " Total = " + f.getTotal());
for (int i = 0; i < 5; i++) {
f.add1(10);
//f.add(10);
System.out.println(Thread.currentThread().getName() + " i = " + i + " Total = " + f.getTotal());
}
}
}
結(jié)果如下:

可以看到線(xiàn)程0和線(xiàn)程1之間只有等待對(duì)方釋放鎖后,自己才能獲得鎖并在Total上加10,他們之間的操作不會(huì)有沖突.
2、 Lock
Lock是java.util.concurrent.locks包下的接口,Lock 實(shí)現(xiàn)提供了比使用synchronized 方法和語(yǔ)句可獲得的更廣泛的鎖定操作
與synchronized的區(qū)別:
Lock可以使用Condition進(jìn)行線(xiàn)程之間的調(diào)度,Synchronized則使用Object對(duì)象本身的notify, wait, notityAll調(diào)度機(jī)制。
Condition(即對(duì)象監(jiān)視器)是Java5以后出現(xiàn)的機(jī)制,它有更好的靈活性,在一個(gè)對(duì)象里面可以有多個(gè)Condition,則線(xiàn)程可以注冊(cè)在不同的Condition,從而可以有選擇性的調(diào)度線(xiàn)程,更加靈活。他并不是一種替代內(nèi)置加鎖的方法,而是當(dāng)內(nèi)置加鎖機(jī)制不適用時(shí),作為一種可選擇的高級(jí)功能,lock接口提供了一種無(wú)條件的、可輪詢(xún)的、定時(shí)的以及可中斷的鎖獲取機(jī)制,所有的加鎖和解鎖方法都是顯示的
Synchronized就相當(dāng)于整個(gè)對(duì)象只有一個(gè)單一的Condition(即該對(duì)象本身)所有的線(xiàn)程都注冊(cè)在它身上
package Lock20170412;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Lock20170412 {
public static void main(String[] args) {
Fun f = new Fun();
NewThread new_thread = new NewThread(f);
Thread thread1 = new Thread(new_thread);
thread1.start();
Thread thread2 = new Thread(new_thread);
thread2.start();
}
}
class Fun {
private int total = 0;
public int getTotal() {
return total;
}
public void add(int i) {
total += i;
}
}
class NewThread implements Runnable {
private Fun f;
private Lock lock = new ReentrantLock();// 鎖對(duì)象
public NewThread(Fun f) {
this.f = f;
}
public void run() {
lock.lock();// 得到鎖
try {
for (int i = 0; i < 5; i++) {
f.add(10);
System.out.println(Thread.currentThread().getName() + " i = " + i + " Total = " + f.getTotal());
}
} finally {
lock.unlock();// 釋放鎖
}
}
}
結(jié)果如下:

可以看到線(xiàn)程0執(zhí)行完畢后才釋放鎖,線(xiàn)程1得到鎖后才開(kāi)始執(zhí)行