同步可以看成排队
每个线程进入同步队列,进行操作时出队,想要继续操作时入队进行等待
如果线程不排队,一拥而上,资源根本不够分配,而且执行的速度够快,无法保证数据的统一性
synchronized:
- 声明方法:锁定当前方法,每个线程使用该方法时都要排队
- 锁定对象:在操作当前对象时,要排队
Runnable和Thread都能实现资源共享 不要被误导
卖门票
public class UnsafeTicket {
public static void main(String[] args) {
BuyTicket buyTicket=new BuyTicket();
new Thread(buyTicket,"小明").start();
new Thread(buyTicket,"张三").start();
new Thread(buyTicket,"黄牛").start();
}
}
class BuyTicket implements Runnable{
private boolean flag=true;
int num=10;
@Override
public void run() {
while(flag){
buy();
}
}
public void stop(){//标识符停止
this.flag=false;
}
}
对买票这个行为来说,票是共享资源 ,所以要考虑的就是如何控制票数
所以就要对买票行为加上同步锁 防止三个线程抢占式买票,导致票的数据不一致性
提醒:现在的电脑性能过高 为了体现多人抢票,最好在购票前加上线程睡眠,以免出现一人全抢的情况
(一个线程调度运行,在这个线程运行至运行完的过程中,其他线程未被调度甚至调度了还没开始跑的情况)
未加同步的买票
public void buy(){
if(num<=0){
stop();
System.out.println("卖完了");
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了第"+num--);
}
7、5、3、1被同时购买,没有票后还买了张0,所以线程不安全
加上同步的买票
//buy操作共享票资源 所以对buy加上同步
public synchronized void buy(){
if(num<=0){
stop();
//System.out.println("卖完了");
return;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了第"+num--);
}
- 加上同步后 每次进行买票操作,三个线程被cpu安排 进入同步队列,依次出队买票 ,以及入队等待买票 不会出现两人同时买票以及买同一张的结果
银行取钱
public class UnsafeBank {
public static void main(String[] args) {
Account account=new Account(100,"结婚基金");
Arawing you=new Arawing(account,50,"你");
Arawing love=new Arawing(account,70,"妻子");
you.start();
love.start();
}
}
class Account {
int money;//余额
String name;//账户
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
class Arawing extends Thread{
Account account;//账户
int arawingMoney;
int nowMoney;
String name;
public Arawing(Account accout,int arawingMoney,String name){
super(name);
this.account=accout;
this.arawingMoney=arawingMoney;
}
@Override
public void run() {
//银行共享账户资源 对账户加上同步
synchronized(account) {
if (account.money - arawingMoney < 0) {
System.out.println(Thread.currentThread().getName() + "余额不足");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money = account.money - arawingMoney;
nowMoney = nowMoney + arawingMoney;
}
//System.out.println(Thread.currentThread().getName()+"取了"+arawingMoney);
System.out.println(this.getName()+"手上有"+nowMoney);
System.out.println("余额"+account.money);
}
}
因为多个人同时使用同一账户取钱,所以该案列需要同步的并非银行,而是账户 同步看成排队
两人同时用同一账户取钱,我在取的时候,
在另一个银行的取钱的妻子,取钱系统必须等待我这边取完才能运行