多线程_15_并发_同步_三大经典案例
线程同步(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,线程被覆盖了
上一篇:
通过多线程提高代码的执行效率例子