1.什么叫线程同步?
统一进行的多个线程共享同一块存储空间,在带来方便的同事,也带来了访问冲突文图,为了保证数据在方法中别访问时的正确性,在访问时加入锁机制,synchronized ,当某一个线程获取得对象的排它锁,独占资源,其他下次讷航必须等待,执行完后,释放锁即可。 存在以下问题:
1.一个线程持有锁会导致其他所有需要次所的线程挂起;
2.再多贤臣竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题
3.如果一个优先高的线程等待一个优先级低的线程释放锁,对导致倒置,引起性能问题。
(多个线程同时操作一个程序,导致线程不安全,所以提出来一个线程同步的概念,实际就是一个等待机制。比如多人买票,食堂吃饭排队,同一张一行卡同一时间用不同的方式取钱等等。)
2.对象的等待池
由于多个需要同时访问的线程去访问同一个方法时,会出现线程不安全的问题,所以会让线程入到对象的等待池。
3.队列和锁
每个对象都拥有一把锁,队列加锁才能保证线程的一个安全性 synchronized ,让多个线程同时进入到对象的等待池,对他们进行排队,一个一个来,根据顺序进行线程开启,当一个线程执行之前,获取一个线程锁,执行完之后,释放锁,进行下一个执行。从而保证了线程的安全。
4.三大不安全案例 (购买车票、银行取钱、ArrayList线程不安全)
package com.thread.security;
/**
* @description: 线程安全测试 ------------- 买票
* @author:wt
* @createTime:2021/9/16 11:13
* @version:1.0
*/
public class ThreadSecurity1 {
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 int ticketNum = 10 ;
boolean flag = true;
@Override
public void run() {
while (flag){
buy();
}
}
private void buy (){
if (ticketNum <= 0){
flag = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"购买到第* "+ ticketNum-- + " *张票!");
}
}
package com.thread.security;
/**
* @description: 银行取钱场景
* @author:wt
* @createTime:2021/9/18 14:57
* @version:1.0
*/
public class ThreadSecurity2 {
public static void main(String[] args) {
Account account = new Account(100,"邮政卡");
// 取钱
Drawing zs = new Drawing(account,50 , "张三");
Drawing ls = new Drawing(account,80 , "李四");
zs.start();
ls.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()+"钱不够了,取不了了!!!!");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 账户的钱
account.money = account.money - drawingMoney;
//手里的钱
nowMoney = nowMoney + drawingMoney;
System.out.println("账户中的钱:" + account.money );
System.out.println(this.getName()+"手里的钱:" + nowMoney );
}
}
package com.thread.security;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 线程不安全
* @author:wt
* @createTime:2021/11/11 17:43
* @version:1.0
*/
public class UnSafeLife {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}