首先引入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