1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 《JAVA300集》多线程_并发基础案例-day21

《JAVA300集》多线程_并发基础案例-day21

时间:2024-08-30 16:18:16

相关推荐

《JAVA300集》多线程_并发基础案例-day21

目录

一、并发与线程同步

二、锁机制

抢票案例

取钱案例

抢票案例优化版本

影院购票案例

抢票案例-面向对象思想

三、并发容器

一、并发与线程同步

并发:同一个对象的多个线程同时操作。

并发有可能引发线程不安全的问题。

线程同步是一种等待机制,用于解决线程不安全问题。

当多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候就可以通过线程同步方法。多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕后,下一个线程再使用

二、锁机制

为了保证数据在多线程访问中的正确性,在访问时加入了锁机制(synchronized),当一个线程获得对象的排它锁,就可以独占资源,其他线程必须等待,这个线程使用完成后释放锁。

使用锁机制有以下问题:(锁会导致性能下降

使用方法: synchronized方法和synchronized块。

每个对象对应一把锁

难点:如何合适的用锁,使得锁不多也不少。同时兼顾安全和性能。

抢票案例

package Thread;/**线程安全:在并发时保证数据的正确性,效率尽可能高* synchronized* 同步方法* */public class SynTest01 {public static void main(String[] args) {SafeWeb12306 web = new SafeWeb12306();new Thread(web,"小黄").start();new Thread(web,"小王").start();new Thread(web,"小蒋").start();}}class SafeWeb12306 implements Runnable{private int ticketNums = 10;private boolean flag = true;@Overridepublic void run() {while(flag){// 模拟抢票延时try{Thread.sleep(200);}catch(InterruptedException e){e.printStackTrace();}test();}}// 锁方法里面跟对象相关的资源,使得只能同时被1个线程访问public synchronized void test(){if(ticketNums<=0){flag = false;return;}System.out.println(Thread.currentThread().getName()+"抢到了"+ticketNums--+"号票");}}

运行结果:

取钱案例

// 账户public class Account {int money;String name;public Account(int money,String name){this.money = money;this.name = name;}}

错误示例-

//模拟取钱(错误示例)public class SynTest02 {public static void main(String[] args) {//账户Account account = new Account(100,"结婚礼金");SafeDrawing you = new SafeDrawing(account,80,"bad的你");SafeDrawing wife = new SafeDrawing(account,90,"happy的小蒋");you.start();wife.start();}}class SafeDrawing extends Thread{Account account; //取钱的账户int drawingMoney; //取出的钱int packetTotal; //口袋里的钱public SafeDrawing(Account account,int drawingMoney,String name){super(name);this.account = account;this.drawingMoney = drawingMoney;}@Overridepublic void run() {test();}//锁这个方法没有用,这个方法类似于取款机,应该去锁账户,因为是账户的对象public synchronized void test(){if(account.money-drawingMoney<0){return;}try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}account.money -= drawingMoney;packetTotal += drawingMoney;System.out.println(this.getName()+"--账户 "+account.money);System.out.println(this.getName()+"--口袋的钱 "+packetTotal);}}

锁方法,是锁方法的对象,方法的默认对象是this

正确示例-

同步块- synchronized(obj){},obj称为同步监视器。 obj推荐使用共享资源。

package Thread;//模拟取钱(正确示例)public class SynBlockTest01 {public static void main(String[] args) {//账户Account account = new Account(1000,"结婚礼金");SynDrawing you = new SynDrawing(account,80,"bad的你");SynDrawing wife = new SynDrawing(account,90,"happy的小蒋");you.start();wife.start();}}class SynDrawing extends Thread{Account account; //取钱的账户int drawingMoney; //取出的钱int packetTotal; //口袋里的钱public SynDrawing(Account account,int drawingMoney,String name){super(name);this.account = account;this.drawingMoney = drawingMoney;}@Overridepublic void run() {test();}//目标锁定账户public void test(){//这个if可以提升代码执行效率if(account.money<=0){return;}synchronized (account) {if (account.money - drawingMoney < 0) {return;}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}account.money -= drawingMoney;packetTotal += drawingMoney;System.out.println(this.getName() + "--账户 " + account.money);System.out.println(this.getName() + "--口袋的钱 " + packetTotal);}}}

运行结果:

同步块可以精准地锁定目标对象。(这个例子中是account)

抢票案例优化版本

/**线程安全:在并发时保证数据的正确性,效率尽可能高* synchronized* 同步块* */public class SynBlockTest03 {public static void main(String[] args) {SynWeb12306 web = new SynWeb12306();new Thread(web,"小黄").start();new Thread(web,"小王").start();new Thread(web,"小蒋").start();}}class SynWeb12306 implements Runnable{private int ticketNums = 10;private boolean flag = true;@Overridepublic void run() {while(flag){// 模拟抢票延时try{Thread.sleep(200);}catch(InterruptedException e){e.printStackTrace();}//test();//falseTest();goodTest();}}public void test() {//synchronized只能锁一个资源synchronized (this) {if (ticketNums <= 0) {flag = false;return;}System.out.println(Thread.currentThread().getName() + "抢到了" + ticketNums-- + "号票");}}//漏锁了一个对象,导致线程依旧不安全public void falseTest() {synchronized ((Integer)ticketNums) {if (ticketNums <= 0) {flag = false;return;}System.out.println(Thread.currentThread().getName() + "抢到了" + ticketNums-- + "号票");}}//线程安全:尽可能锁定合理的范围,这样可以提升性能public void goodTest() {//双重检测,主要考虑的是临界值的问题if (ticketNums <= 0) { //考虑的是没有票的情况flag = false;return;}synchronized (this) {if (ticketNums <= 0) { //考虑的是最后1张票flag = false;return;}System.out.println(Thread.currentThread().getName() + "抢到了" + ticketNums-- + "号票");}}}

影院购票案例

package Thread;import java.util.ArrayList;import java.util.List;public class HappyCinema2 {public static void main(String[] args) {//影院可用的位置List<Integer> avaliable = new ArrayList<Integer>();avaliable.add(1);avaliable.add(2);avaliable.add(3);avaliable.add(4);//顾客需要的位置List<Integer> seats1 = new ArrayList<Integer>();seats1.add(1);seats1.add(2);List<Integer> seats2 = new ArrayList<Integer>();seats2.add(3);seats2.add(5);HCinema c = new HCinema(avaliable,"万达影院");new Thread(new HappyCustomer(c,seats1),"小张和小机智").start();new Thread(new HappyCustomer(c,seats2),"小赵").start();System.out.println("欢迎光临!");}}//顾客class HappyCustomer implements Runnable{HCinema hinema;List<Integer> seats;public HappyCustomer(HCinema hinema, List<Integer> seats) {this.hinema = hinema;this.seats = seats;}@Overridepublic void run() {synchronized (hinema){System.out.println(Thread.currentThread().getName()+" -想要购买的位置为:"+seats);boolean flag = hinema.bookTickets(seats);if(flag){System.out.println("出票成功 "+ Thread.currentThread().getName()+" -购买的位置为:"+seats+"\n");}else{System.out.println("出票失败 "+ Thread.currentThread().getName()+" -购买失败,没位置了");}}}}//影院class HCinema{List<Integer> avaliable; //可用的位置String name;public HCinema(List<Integer> avaliable, String name) {this.avaliable = avaliable;this.name = name;}//购票public boolean bookTickets(List<Integer> seats){System.out.println(this.name+"当前可用位置为: " + avaliable);//两个容器的比较List<Integer> copy = new ArrayList<Integer>();copy.addAll(avaliable);//相减copy.removeAll(seats);//判断是否成功if(avaliable.size()-copy.size()!=seats.size()){return false;}else{avaliable = copy;return true;}}}

运行结果:

抢票案例-面向对象思想

public class Happy12306 {public static void main(String[] args) {Web123066 w = new Web123066(2,"铁路局");new Passenger(w,"小张",2).start();new Passenger(w,"小机智",2).start();}}//乘客 (继承,作为Thread的子代理)class Passenger extends Thread{int seats;public Passenger(Runnable target, String name, int seats) {super(target,name);this.seats = seats;}}//火车票网class Web123066 implements Runnable{int avaliable; //可用的位置String name;public Web123066(int avaliable, String name) {this.avaliable = avaliable;this.name = name;}@Overridepublic void run() {Passenger p = (Passenger)Thread.currentThread(); //把当前线程强转为当前子类boolean flag = this.bookTickets(p.seats);if(flag){System.out.println("出票成功 "+ Thread.currentThread().getName()+" -购买位置数量为:"+p.seats);}else{System.out.println("出票失败 "+ Thread.currentThread().getName()+" -购买失败,没位置了");}}//购票public synchronized boolean bookTickets(int seats){//购票延迟try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(this.name+"当前可用位置为: " + avaliable);if(seats>avaliable){return false;}avaliable -=seats;return true;}}

运行结果:

Passenger p = (Passenger)Thread.currentThread(); //把当前线程强转为当前子类

三、并发容器

java中有自带的并发容器,名为util.concurrent

import java.util.concurrent.*

import java.util.concurrent.CopyOnWriteArrayList;/** 并发安全操作容器* */public class SynContainer {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();for(int i=0;i<1000;i++){new Thread(()-> list.add(Thread.currentThread().getName())).start();}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。