5.1 并发问题 → 三大不安全案例
5.1.1 三人共同买票(不安全买票)
package www.muquanyu.syn;
//不安全的买票 案例
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"黄牛").start();
new Thread(station,"小明").start();
new Thread(station,"老师").start();
}
}
class BuyTicket implements Runnable {
//票
private int ticket = 10;
@Override
public void run() {
//买票
while(ticket > 0)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->买到了第"+(ticket--)+"张票");
}
}
}
明显会有 资源 抢夺的问题,这里会 出现 资源的重复,这是根本不可能的事情!!(所以这是 并发问题 的发生。)
5.1.2 两人共同取款(不安全取款)
package www.muquanyu.syn;
public class UnsafeBank {
public static void main(String[] args) {
//账户创建
Account account = new Account(100,"结婚基金");
Drawing you = new Drawing(account,50,"你");
Drawing grilFriend = new Drawing(account,100,"你的女朋友");
you.start();
grilFriend.start();
}
}
//账户(Java 版本的结构体)
class Account{
int money;//余额
String name;//卡名
public Account( int money,String name)
{
this.money = money;
this.name = name;
}
public Account(String name)
{
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(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money -= drawingMoney;
//你手里的钱
nowMoney += drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
System.out.println(this.getName()+"手里的钱:"+nowMoney);
}
}
嗯? 那 五十万呢??我草?
… 全没了。。
过分了啊,负数。。
综上所述,这些操作 都是 不安全的,会出现 并发问题。
5.1.3 线程不安全的集合
package www.muquanyu.syn;
import java.util.ArrayList;
import java.util.List;
public class UnsafeList {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<String>();
for(int i = 0;i < 10000;++i)
{
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
System.out.println(list.size());
}
}
我们往往 处理 数据,是不是都是在 集合里面处理的呀?那比如说我们 每一个数据 都开个 线程处理!我们的数据 还会是正确的吗?
为什么是不正确的呢?答:因为多个线程 同时 对 一个 List 集合 进行 存储的操作!!发生了 并发问题。
5.1.4 CopyOnWriteArrayList(JUC)
我们来说一个 JUC(Java 并发包)下的 安全 集合。
Callable 这个可能会成为 新时代宠儿的 接口,就是 JUC 包下面的。
package www.muquanyu.syn;
import java.util.concurrent.CopyOnWriteArrayList;
//JUC 安全类型的 集合
public class JUCDemo {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for(int i = 0;i < 10000;++i)
{
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(100);
System.out.println(list.size());
}
}
JUC 包下 的 CopyOnWriteArrayList<> 是 一个 安全的 集合。