首先引入gitHub上面一個解釋
一.原理分析
1. 同步一個代碼塊
public void func() {
synchronized (this) {
// ...
}
}
它只作用於同一個對象,如果調用兩個對象上的同步代碼塊,就不會進行同步。
2. 同步一個方法
public synchronized void func () {
// ...
}
它和同步代碼塊一樣,作用於同一個對象。
3. 同步一個類
public void func() {
synchronized (SynchronizedExample.class) {
// ...
}
}
作用於整個類,也就是說兩個線程調用同一個類的不同對象上的這種同步語句,也會進行同步
另外我覺得這裏面不只是鎖類單一的,只要是常量不變的即可,是爲了鎖唯一,也就是一個線程進去之後,獲得了這把鎖,因爲這把鎖唯一,那麼只有這個線程裏面所有的東西都執行完畢,纔會下一個線程進入
4.同步靜態方法
public synchronized static void fun() {
// ...
}
二.DEMO
public class Ticket {
public static void main(String[] args) {
GetTicket getTicket=new GetTicket();
Thread thread1=new Thread(getTicket,"我");
Thread thread2=new Thread(getTicket,"張");
Thread thread3=new Thread(getTicket,"黃牛");
thread1.start();
thread2.start();
thread3.start();
}
}
class GetTicket implements Runnable{
private int ticketNum=10;
boolean flag=true;
@Override
public void run() {
while(flag){
buy();
}
}
//synchronized 同步方法 鎖的是this
private synchronized void buy(){
if(ticketNum<=0){
flag=false;
return ;
}
//模擬延時
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"取到了"+ticketNum--);
}
}
這裏可以看到只新建了一個對象,也就是隻有一份資源,三個代理去搶,所以鎖方法即可。
如果改成不同的對象,那麼這個鎖就失去意義了,相當於兩份資源,如果還是鎖的方法,就不是同步了
public class Ticket {
public static void main(String[] args) {
GetTicket getTicket=new GetTicket();
GetTicket getTicket2=new GetTicket();
Thread thread1=new Thread(getTicket,"我");
Thread thread2=new Thread(getTicket2,"張");
thread1.start();
thread2.start();
}
}
class GetTicket implements Runnable{
private int ticketNum=10;
boolean flag=true;
@Override
public void run() {
while(flag){
buy();
}
}
//synchronized 同步方法 鎖的是this
private synchronized void buy(){
if(ticketNum<=0){
flag=false;
return ;
}
//模擬延時
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"取到了"+ticketNum--);
}
}
這個時候只有synchronized(this)纔可以。
再來看一個例子
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(500,"結婚基金");
Drwaing you=new Drwaing(account,50,"你");
Drwaing wife=new Drwaing(account,100,"妻子");
you.start();
wife.start();
}
}
class Account{
int money;//餘額
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
class Drwaing extends Thread{
Account account;
int drawingMoney;
int nowMoney;
public Drwaing(Account account,int drawingMoney,String name){
super(name);
this.account=account;
this.drawingMoney=drawingMoney;
}
@Override
//如果在方法上面加鎖,那麼鎖的就是這個銀行this,但實際上我們操作的是account對象
public void run() {
synchronized (UnsafeBank.class) {
if (account.money - drawingMoney < 0) {
System.out.println(Thread.currentThread().getName() + "錢不夠");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money = account.money - drawingMoney;
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name + "餘額" + account.money);
System.out.println(this.getName() + "手裏的錢" + nowMoney);
}
}
}
這個因爲對象是兩個,如果鎖的是方法,那麼就不安全了
參考GitHUb