zoukankan      html  css  js  c++  java
  • Java多线程,实现卖电影票的业务

    本篇重点:多线程共享资源时发生的互斥问题

    一般的我们售卖电影票或者火车票时会有多个窗口同时买票,

    我们来看测试代码:主方法new一个Ticket(一个堆),之后三个线程来启动(三个窗口买票)

    class Ticket implements Runnable{
    	private static int ticket=10;
    	@Override
    	public void run() {
    		for(int i=1;i<=100;i++){
    			System.out.println(Thread.currentThread().getName()+" - 开始买票");
    			
    			synchronized(this){ //同步代码块+对象锁
    				System.out.println(Thread.currentThread().getName()+" - 买了第"+ticket+"张票");
    				ticket--;
    			}
    			
    			System.out.println(Thread.currentThread().getName()+" - 结束买票");
    			
    			if(ticket<=0){break;}
    		}
    	}
    }
    public class Demo {
    	public static void main(String[] args) {
    		Ticket ticket=new Ticket();
    		new Thread(ticket,"1号窗口").start();
    		new Thread(ticket,"2号窗口").start();
    		new Thread(ticket,"3号窗口").start();
    	}
    }

      同步块内的代码是原子性的,在没有执行完所有语句时是不会出让CPU的。

    在分析以上代码前,我们先简化模型。

    class Ticket implements Runnable{
    	@Override
    	public void run() {
    		for(int i=1;i<=5;i++){
    			System.out.println(Thread.currentThread().getName()+" - A");
    			System.out.println(Thread.currentThread().getName()+" - B");
    			System.out.println(Thread.currentThread().getName()+" - C");
    		}
    	}
    }
    public class Demo {
    	public static void main(String[] args) {
    		Ticket ticket=new Ticket();
    		new Thread(ticket,"t1").start();
    		new Thread(ticket,"t2").start();
    		new Thread(ticket,"t3").start();
    	}
    }
    

      运行如图:

    t1 - A
    t2 - A
    t3 - A
    t3 - B
    t1 - B
    t3 - C
    t2 - B
    t2 - C
    t3 - A
    t1 - C
    t1 - A
    t1 - B
    t1 - C
    t3 - B
    t3 - C
    t3 - A
    t2 - A
    t3 - B
    t1 - A
    t3 - C
    t2 - B
    t3 - A
    t1 - B
    t3 - B
    t2 - C
    t3 - C
    t1 - C
    t3 - A
    t2 - A
    t2 - B
    t2 - C
    t2 - A
    t2 - B
    t2 - C
    t2 - A
    t2 - B
    t3 - B
    t1 - A
    t3 - C
    t2 - C
    t1 - B
    t1 - C
    t1 - A
    t1 - B
    t1 - C

    每次运行结果都会不一样,因为轮流抢占CPU不是我们能控制的。

    图解分析:

     

    由分析我们得出大概是以一条语句作为基本单位来执行,若多条语句需要作为一个原子性的整理,就需要加互斥锁。

    原理大致如图:

    加锁的这段区域被称为“互斥区”,里面的代码必须整理执行完毕才会释放锁,让其他线程切入进来。

    synchronized具有加锁的功能,实现比较简单。

    我们再看卖票的代码:

    class Ticket implements Runnable{
    	private static int ticket=10;
    	@Override
    	public void run() {
    		for(int i=1;i<=100;i++){
    			try {
    				Thread.sleep(500); //线程休眠500毫秒,以便观察输出
    			} catch (InterruptedException e) { //需要处理异常
    				e.printStackTrace();
    			}
    			
    			synchronized(this){ //同步代码块+对象锁(this表示对象锁)
    				if(ticket<=0){break;}
    				System.out.println(Thread.currentThread().getName()+" 买了第"+ticket+"张票");
    				ticket--;
    			}
    		}
    	}
    }
    public class Demo {
    	public static void main(String[] args) {
    		Ticket ticket=new Ticket();
    		new Thread(ticket,"1号窗口").start();
    		new Thread(ticket,"2号窗口").start();
    		new Thread(ticket,"3号窗口").start();
    	}
    }
    

      运行如图:

  • 相关阅读:
    高效DevOps的10项实践
    Qlik Sense Desktop
    CQRS架构
    Scala开发环境搭建与资源推荐
    Scala是一门现代的多范式编程语言
    四种优秀架构
    干净的架构The Clean Architecture
    自动更改IP地址反爬虫封锁,支持多线程(转)
    ActiveMQ源码架构解析第一节(转)
    grails的controller和action那点事---远程调试groovy代码
  • 原文地址:https://www.cnblogs.com/mengxinrenyu/p/8095336.html
Copyright © 2011-2022 走看看