1、并发 :
同一个对象被多个线程同时操作,如十个人同时抢一张火车票
2、线程同步机制
-线程同步
现实生活中,我们会遇到 ” 同一个资源 , 多个人都想使用 ” 的问题 , 比如,食堂排队打饭 , 每个人都想吃饭 , 最天然的解决办法就是 , 排队 ,一个个来。
处理多线程问题时 , 多个线程访问同一个对象 , 并且某些线程还想修改这个对象(如银行取钱),这时候我们就需要线程同步 , 线程同步其实就是一种等待机制 , 多个需要同时访问此对象的线程进入这个对象的等待池形成队列, 等待前面线程使用完毕 , 下一个线程再使用。
- 队列 和 锁
为了保证线程同步 的安全性需要:队列+锁
由于同一进程的多个线程共享同一块存储空间 , 在带来方便的同时,也带来了访问冲突问题 , 为了保证数据在方法中被访问时的正确性 , 在访问时加入锁机制 synchronized , 当一个线程获得对象的排它锁 , 独占资源 , 其他线程必须等待 , 使用后释放锁即可。同时使用锁存在以下问题 :
一个线程持有锁会导致其他所有需要此锁的线程挂起 ;
在多线程竞争下 , 加锁 , 释放锁会导致比较多的上下文切换和调度延时,引起性能问题 ;
如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置 , 引起性能问题
3、三大不安全案例
- 不安全的买票
//不安全的买票
//线程不安全,有零和负数
public class unsafeBuyTickets {
public static void main(String[] args) {
BuyTickets buyTickets = new BuyTickets();
new Thread(buyTickets,"凸凸").start();
new Thread(buyTickets,"凹凹").start();
new Thread(buyTickets,"黄牛党").start();
}
}
class BuyTickets implements Runnable{
//票
private int ticketsNums = 10;
private Boolean flag = true;//外部停止方式
@Override
public void run() {
buy();
}
public void buy(){
while(flag){
if(ticketsNums <= 0){
flag = false;
return;
}
//模拟时延
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketsNums-- + "张票");
}
}
}
运行截图:
- 不安全的取钱
//两个人去银行取钱,账户
public class unsafeBank {
public static void main(String[] args) {
Account account = new Account(10000,"恋爱基金");
Drawing me = new Drawing(account,9000,2000);
Drawing boyFriend = new Drawing(account,2000,8000);
new Thread(me,"我").start();
new Thread(boyFriend,"男朋友").start();
}
}
//账户
class Account{
int money;//余额
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//模拟银行取钱
class Drawing implements Runnable{
//账户
Account account;
//取多少钱
int drawingMoney;
//手里有多少钱
int nowMoney;
public Drawing(Account account, int drawingMoney, int nowMoney) {
this.account = account;
this.drawingMoney = drawingMoney;
this.nowMoney