线程同步机制
并发:同一个对象被多个线程同时操作
线程同步:
线程不安全案例1:
//不安全的买票 可能出现负数票,或者抢到了同一张票
public class UnsafeBuyTicket implements Runnable{
private int ticketNums=10; //票
boolean flag=true; //外部停止方式
@Override
public void run() {
while (flag){
buy();
}
}
private void buy(){
if(ticketNums<0){
flag=false;
return;
}
//模拟延时
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");
}
public static void main(String[] args) {
UnsafeBuyTicket unsafeBuyTicket=new UnsafeBuyTicket();
new Thread(unsafeBuyTicket,"学生").start();
new Thread(unsafeBuyTicket,"老师").start();
new Thread(unsafeBuyTicket,"黄牛党").start();
}
}
线程不安全案例2:
//不安全的取钱 //两个人去银行取钱 public class UnsafeBank { public static void main(String[] args) { Account account=new Account(100,"结婚基金"); Drawing you=new Drawing(account,50,"你"); Drawing girlFriend=new Drawing(account,100,"grilFriend"); you.start(); girlFriend.start(); } } //账户 class Account{ int money; //余额 String name; //卡名 public Account(int money, String name) { this.money = money; this.name = name; } } //银行:模拟取款 class Drawing extends Thread { Account account; //账户 int drawingMoney; //取了多少钱 int nowMoney; //现在手里有多少钱 public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //取钱 @Override public void run() { if(account.money-drawingMoney<0){ System.out.println(Thread.currentThread().getName()+"钱不够了,取不了了"); } 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); } }
线程不安全案例3
import java.util.ArrayList; import java.util.List; public class UnsafeList { public static void main(String[] args) { List<String> list=new ArrayList<>(); for(int i=0;i<10000;i++){ new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
同步方法
同步方法弊端
解决方案一:在方法中使用 synchronized锁住方法 对应上面第一个案例
//不安全的买票 public class UnsafeBuyTicket implements Runnable{ private int ticketNums=10; //票 boolean flag=true; //外部停止方式 @Override public void run() { while (flag){ buy(); //模拟延时 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } private synchronized void buy(){ if(ticketNums<1){ flag=false; return; } System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票"); } public static void main(String[] args) { UnsafeBuyTicket unsafeBuyTicket=new UnsafeBuyTicket(); new Thread(unsafeBuyTicket,"学生").start(); new Thread(unsafeBuyTicket,"老师").start(); new Thread(unsafeBuyTicket,"黄牛党").start(); } }
同步块 锁的对象就是变化的量,需要增删改的对象
//不安全的取钱 //两个人去银行取钱 public class UnsafeBank { public static void main(String[] args) { Account account=new Account(100,"结婚基金"); Drawing you=new Drawing(account,50,"你"); Drawing girlFriend=new Drawing(account,100,"grilFriend"); you.start(); girlFriend.start(); } } //账户 class Account{ int money; //余额 String name; //卡名 public Account(int money, String name) { this.money = money; this.name = name; } } //银行:模拟取款 class Drawing extends Thread { Account account; //账户 int drawingMoney; //取了多少钱 int nowMoney; //现在手里有多少钱 public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //取钱 @Override public void run() { synchronized(account){ 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); } } }