Java------多线程_并发_非同步_三大经典案例 (七)
线程同步要保证数据的安全性和正确性,以及性能。
代码上使用synon
高性能、高并发、高可用
并发:同一个对象多个线程同时操作。
并发的三个条件缺一不可,同一对象、多个线程、同时操作。
之前模拟抢票代码时,多个线程同时对一份资源进行操作,导致出现两种数据错误的表现:
1.抢到最后出现负数的情况。
2.抢的过程中出现多个线程使用同一票数的情况。多个线程从主存空间拷贝到各自工作内存中数据不一致。
/**
* 线程不安全:数据出现负数、出现线程使用相同的数
*/
public class ThreadSyn {
public static void main(String[] args) {
UnSafe threadTest01 = new UnSafe();
//多个代理,加入名称区分
new Thread(threadTest01,"thread01").start();
new Thread(threadTest01,"thread02").start();
new Thread(threadTest01,"thread03").start();
}
}
class UnSafe implements Runnable{
private int tickNums = 10;
private Boolean flag = true;
@Override
public void run(){
while (flag){
test();
}
}
public void test(){
if (tickNums<0){
flag = false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+tickNums--);
}
}
案例二:同时取钱的例子,即使在取钱时,加入判断,依然能取出去,造成账户余额为负数,两个人都能取到钱。
public class ThreadSyn02 {
public static void main(String[] args) {
Account account = new Account(100,"家庭基金");
Draw draw = new Draw(account,70,"男人");
Draw draw2 = new Draw(account,70,"女人");
draw.start();
draw2.start();
}
}
//账户 Account
class Account{
public int money;
public String name;
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
class Draw extends Thread{
Account account; //账户
int drawingMoney;//取的钱
int packetTotal;//口袋里的钱
public Draw(Account account,int drawingMoney,String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
@Override
public void run() {
//加上判断,当银行余额-取钱小于0时,不让取
if (account.money-drawingMoney<0){
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money -= drawingMoney;
packetTotal += drawingMoney;
System.out.println(this.getName()+"---->账户余额"+account.money);
System.out.println(this.getName()+"---->口袋余额"+packetTotal);
}
}
案例三:容器一会出现线程不安全
/**
* 容器不安全例子
*/
public class ThreadSyn03 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
for (int i = 0 ; i<100;i++){
new Thread(()->{
arrayList.add(Thread.currentThread().getName());
}).start();
}
//最终打印结果,不到100
System.out.println(arrayList.size());
}
}