线程同步(synchronized):在一个多线程环境中,我们要保证数据的准确性和安全性,同时还要提高它的性能。
并发:指同一对象多个线程同时操作
不安全的案例一:12306买票
package com.cb.thread.day03;
public class UnsafeTest01 {
public static void main(String[] args) {
//一份资源
Web12306 web = new Web12306();
System.out.println(Thread.currentThread().getName());
//三个代理
new Thread(web,"码畜").start(); //加上名字,区分线程
new Thread(web,"码农").start();
new Thread(web,"码蟥").start();
}
}
class Web12306 implements Runnable{
private int ticketNums = 10; //99张票
private boolean flag = true;
@Override
public void run() {
while(flag){
test();
}
}
public void test(){
if(ticketNums<0){
flag= false;
return;
}
try {
Thread.sleep(200);//模拟延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Thread.currentThread().getName()谁运行run就是代表谁
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
运行结果1:
运行结果2:
从结果上看出线程不安全,数据有负数,数据相同,负数怎么来的呢,假如就剩下最后一张票了,ABC都进来了抢票,假设B优先进来,等待了200毫秒,然后AC也进来等待了200毫秒,此时B醒了,把最后一张票拿走了,C醒了只能拿0,A醒了拿-1,就有了负值。相同票是怎么出现呢,以前说过每个线程都有自己的工作空间,它们都跟主存空间都有交互,假如A先把主存的1拷贝过来,还没来的及修改数据,B也把主存的1拷贝过来,所以就会遇到两张相同的值。
案例二:
package com.cb.thread.day03;
public class UnsafeTest02 {
public static void main(String[] args) {
//账户
Account account = new Account(100, "结婚礼金");
Drawing you = new Drawing(account, 70, "男方");
Drawing wife = new Drawing(account, 80, "女方");
you.start();
wife.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 packetTotal;//口袋里面的钱
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) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.money -=drawingMoney;
packetTotal +=drawingMoney;
System.out.println(this.getName()+"-->"+"账户余额为"+account.money);
System.out.println(this.getName()+"口袋里面的钱-->"+packetTotal);
}
}
运行结果:
结果为-50,怎么来的呢,100-70-80=-50;
案例三:将一万个线程名字放进容器中
package com.cb.thread.day03;
import java.util.ArrayList;
import java.util.List;
public class UnsafeTest03 implements Runnable{
static List<String> list = new ArrayList<String>();
public static void main(String[] args) {
for (int i = 0; i < 10000; i++) {
UnsafeTest03 u03 =new UnsafeTest03();
Thread t = new Thread(u03);
t.start();
}
System.out.println(list.size());
}
@Override
public void run() {
list.add(Thread.currentThread().getName());
}
}
运行结果:结果为9956,线程被覆盖了