多线程经典案例

售票服务

public class Station extends Thread {

        // 通过构造方法给线程名字赋值
        public Station(String name) {
             super(name);// 给线程名字赋值
        }

        // 为了保持票数的一致,票数要静态
        static int tick = 20;

        // 创建一个静态钥匙
        static Object ob = new Object();//值是任意的

        // 重写run方法,实现买票操作
        @Override
        public void run() {
            while (tick > 0) {
                synchronized (ob) {// 这个很重要,必须使用一个锁,
                    // 进去的人会把钥匙拿在手上,出来后才把钥匙拿让出来
                    if (tick > 0) {
                        System.out.println(getName() + "卖出了第" + tick + "张票");
                        tick--;
                    } else {
                        System.out.println("票卖完了");
                    }
                }
                try {
                     sleep(1000);//休息一秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
    }

}
public class MainClass {
    /**
     * java多线程同步锁的使用
     * 示例:三个售票窗口同时出售10张票
     * */
    public static void main(String[] args) {
        //实例化站台对象,并为每一个站台取名字
         Station station1=new Station("窗口1");
         Station station2=new Station("窗口2");
         Station station3=new Station("窗口3");

        // 让每一个站台对象各自开始工作
         station1.start();
         station2.start();
         station3.start();

    }

}

银行取款

public class Bank {

    // 假设一个账户有1000块钱
    static int money = 1000;

    // 柜台Counter取钱的方法
    public void Counter(int money) {// 参数是每次取走的钱
        Bank.money -= money;//取钱后总数减少
        System.out.println("A取走了" + money + "还剩下" + (Bank.money));
    }

    // ATM取钱的方法
    public void ATM(int money) {// 参数是每次取走的钱
        Bank.money -= money;//取钱后总数减少
        System.out.println("B取走了" + money + "还剩下" + (Bank.money));
    }

}
public class PersonA extends Thread {
    // 创建银行对象
    Bank bank;

    // 通过构造器传入银行对象,确保两个人进入的是一个银行
    public PersonA(Bank bank) {
         this.bank = bank;
    }

    //重写run方法,在里面实现使用柜台取钱
    @Override
        public void run() {
            while (Bank.money >= 100) {
                bank.Counter(100);// 每次取100块
            try {
                sleep(100);// 取完休息0.1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class PersonB extends Thread {
    // 创建银行对象
    Bank bank;

    // 通过构造器传入银行对象,确保两个人进入的是一个银行
    public PersonB(Bank bank) {
        this.bank = bank;
    }

    // 重写run方法,在里面实现使用柜台取钱
    @Override
    public void run() {
        while (Bank.money >= 200) {
            bank.ATM(200);// 每次取200块
            try {
                sleep(100);// 取完休息0.1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
public class MainClass {
    /**
     * 两个人AB通过一个账户A在柜台取钱和B在ATM机取钱
     * */
    public static void main(String[] args) {
        // 实力化一个银行对象
        Bank bank = new Bank();
        // 实例化两个人,传入同一个银行的对象
        PersonA pA = new PersonA(bank);
        PersonB pB = new PersonB(bank);
        // 两个人开始取钱
        pA.start();
        pB.start();

    }

}

龟兔赛跑

public abstract class Animal extends Thread{

    public double length=20;//比赛的长度

    public abstract void runing();//抽象方法需要子类实现

    //在父类重写run方法,在子类只要重写running方法就可以了
    @Override
    public void run() {
        super.run();
        while (length>0) {
             runing();
        }
    }

    //在需要回调数据的地方(两个子类需要),声明一个接口
    public static interface Calltoback{
        public void win();
    }

    //2.创建接口对象
    public Calltoback calltoback;

}
public class Rabbit extends Animal {

    public Rabbit() {
        setName("兔子");// Thread的方法,给线程赋值名字
    }

    // 重写running方法,编写兔子的奔跑操作
    @Override
    public void runing() {
        // 跑的距离
        double dis = 0.5;
        length -= dis;//跑完后距离减少
        if (length <= 0) {
            length = 0;
            System.out.println("兔子获得了胜利");
            //给回调对象赋值,让乌龟不要再跑了
            if (calltoback != null) {
                calltoback.win();
            }
        }
        System.out.println("兔子跑了" + dis + "米,距离终点还有" + (int)length + "米");

        if (length % 2 == 0) {// 两米休息一次
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Tortoise extends Animal {

    public Tortoise() {
        setName("乌龟");// Thread的方法,给线程赋值名字
    }

    // 重写running方法,编写乌龟的奔跑操作
    @Override
    public void runing() {
        // 跑的距离
        double dis = 0.1;
        length -= dis;
        if (length <= 0) {
            length = 0;
            System.out.println("乌龟获得了胜利");
            // 让兔子不要在跑了
            if (calltoback != null) {
                calltoback.win();
            }
        }
        System.out.println("乌龟跑了" + dis + "米,距离终点还有" + (int) length + "米");
        try {
            sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class LetOneStop implements Calltoback {

    // 动物对象
    Animal an;

    // 获取动物对象,可以传入兔子或乌龟的实例
    public LetOneStop(Animal an) {
        this.an = an;
    }

    //让动物的线程停止
    @Override
    public void win() {
        // 线程停止
        an.stop();
    }

}
public class MainClass {
    /**
     * 龟兔赛跑:20米
     * */
    public static void main(String[] args) {
        //实例化乌龟和兔子
        Tortoise tortoise = new Tortoise();
        Rabbit rabbit = new Rabbit();
        //回调方法的使用,谁先调用calltoback方法,另一个就不跑了
        LetOneStop letOneStop1 = new LetOneStop(tortoise);
        rabbit.calltoback = letOneStop1;//让兔子的回调方法里面存在乌龟对象的值,可以把乌龟stop
        LetOneStop letOneStop2 = new LetOneStop(rabbit);
        tortoise.calltoback = letOneStop2;//让乌龟的回调方法里面存在兔子对象的值,可以把兔子stop
        //开始跑
        tortoise.start();
        rabbit.start();

    }

}

生产者消费者模式

public class Food {
    String name="";
    //通过构造方法传入食物的名字
    public Food(String name) {
        this.name=name;
    }
    //get、set 方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public class KFC {

    //食物的种类
    String[] names = { "薯条", "烧板", "鸡翅", "可乐" };

    //生产的最大值,到达后可以休息
    static final int Max = 20;

    //存放食物的集合
    List foods = new ArrayList();

    // 生产食物的方法
    public void prod(int index) {
        synchronized (this) {
            // 如果食物数量大于20
            while (foods.size() > Max) {
                System.out.println("食材够了");
                this.notifyAll();//这个唤醒是针对生产者和消费者,有all
                try {
                    String name=Thread.currentThread().getName();
                    this.wait();//这个唤醒是针对生产者,没有all
                    System.out.println("生产者:"+name);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 开始生产食物食物//有一点要注意的
            System.out.println("开始生产食物");
            for (int i = 0; i < index; i++) {
                Food food = new Food(names[(int) (Math.random() * 4)]);
                foods.add(food);
                System.out.println("生产了" + food.getName() + foods.size());
            }
        }
    }
public void consu(int index) {
        synchronized (this) {
            while (foods.size() < index) {
                System.out.println("食材不够了");
                this.notifyAll();//这个唤醒是针对生产者和消费者,有all
                try {
                    String name=Thread.currentThread().getName();
                    this.wait();//这个唤醒是针对消费者,没有all
                    System.out.println("消费者:"+name);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 足够消费
            System.out.println("开始消费");
            for (int i = 0; i < index; i++) {
                Food food = foods.remove(foods.size() - 1);
                System.out.println("消费了一个" + food.getName() + foods.size());
            }
        }
    }
}
public class Customers extends Thread{
    KFC kfc;
    //KFC要传入,保证每一个服务员和用户在同一个KFC对象内
    public Customers(KFC kfc) {
        this.kfc=kfc;
    }
    @Override
    public void run() {
        int size=(int)(Math.random()*5);//每次要消费的食物的数量
        while (true) {
            kfc.consu(size);//在消费的方法里面传入参数
        }

    }
}
public class Waiter extends Thread{
    KFC kfc;
    //KFC要传入,保证每一个服务员和用户在同一个KFC对象内
    public Waiter(KFC kfc) {
        this.kfc=kfc;
    }
    @Override
    public void run() {
        int size=(int)(Math.random()*5)+5;//每次生产的数量
        while (true) {
            kfc.prod(size);//传入每次生产的数量
        }

    }
}
public class MainClass {
    /**
     * 生产者消费者模式
     *
     * */
    public static void main(String[] args) {

        // 只实例化一个KFC对象,保证每一个服务员和用户在同一个KFC对象内
        KFC kfc = new KFC();

        //实例化4个客户对象
        Customers c1 = new Customers(kfc);
        Customers c2 = new Customers(kfc);
        Customers c3 = new Customers(kfc);
        Customers c4 = new Customers(kfc);

        //实例化3个服务员对象
        Waiter waiter1 = new Waiter(kfc);
        Waiter waiter2 = new Waiter(kfc);
        Waiter waiter3 = new Waiter(kfc);

        //让所有的对象的线程都开始工作
        waiter1.start();
        waiter2.start();
        waiter3.start();
        c1.start();
        c2.start();
        c3.start();
        c4.start();
    }

}

 设计四个线程对象对同一个数据进行操作

public class ThreadAddSub extends Thread {
    //判断要进行的操作
    boolean operate = true;
    //要操作的数
    static int sum = 0;

    // 把操作运算通过构造方法传进来
    public ThreadAddSub(boolean operate) {
        super();
        this.operate = operate;
    }

    @Override
    public void run() {
        super.run();
        while (true) {
            if (operate) {
                sum+=5;
                System.out.println("加后,sum="+sum);
            } else {
                sum-=4;
                System.out.println("减后,sum="+sum);
            }
            try {
                sleep(500);// 睡眠0.5秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
public class MainClass {
    /**
     * (线程同步)
     * */
    public static void main(String[] args) {

        //创建一个存放ThreadAddSub对象的数组
        ThreadAddSub[] tSub=new ThreadAddSub[4];
        for (int i = 0; i < tSub.length; i++) {

        //把实例化ThreadAddSub对象赋值到数组内
        //第一三个是true,二四个是false
        tSub[i]=new ThreadAddSub(i%2==0?true:false);

        //让线程开始工作
        tSub[i].start();
        }

    }

}

电影院选座

public class HappyCinema2 {
    public static void main(String[] args) {
        Cinema2 c = new Cinema2(Arrays.asList(1,2,3,4,5), "happy cinema");
        new Thread(new Customer2(c,Arrays.asList(1,2))).start();
        new Thread(new Customer2(c,Arrays.asList(3,5))).start();
    }
}

class Cinema2{
    private List<Integer> available;
    private String name;

    Cinema2(List<Integer> available, String name){
        this.available = available;
        this.name = name;
    }

    boolean bookTickets(List<Integer> seats) {
        System.out.println("可用位置:" + available);
        List<Integer> copy = new ArrayList<>(available);
        copy.removeAll(seats);
        if (copy.size() + seats.size() == available.size()) {
            available = copy;
            return true;
        }
        return false;
    }
}

class Customer2 implements Runnable{
    private final Cinema2 cinema;
    private List<Integer> seats;

    Customer2(Cinema2 cinema, List<Integer> seats) {
        this.cinema = cinema;
        this.seats = seats;
    }

    @Override
    public void run() {
        synchronized (cinema) {
            boolean flag = cinema.bookTickets(seats);
            if (flag) {
                System.out.println("出票成功" + seats + "个位置");
            } else {
                System.out.println("出票失败,位置不够");
            }
        }
    }
}

原文地址:https://www.cnblogs.com/aikf/p/10204937.html

时间: 2024-10-14 01:45:25

多线程经典案例的相关文章

java多线程经典案例

/** * 典型案例:子线程执行10次,主线程执行100次,两者交替50次. */ package cn.itcast.lesson4; public class TestWaitNotify { public static void main(String[] args){ final Business business= new Business(); new Thread( new Runnable() { public void run() { for(int i=1;i<=50;i++

多线程十大经典案例之一 双线程读写队列数据

本文配套程序下载地址为:http://download.csdn.net/detail/morewindows/5136035 转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8646902 欢迎关注微博:http://weibo.com/MoreWindows 在<秒杀多线程系列>的前十五篇中介绍多线程的相关概念,多线程同步互斥问题<秒杀多线程第四篇一个经典的多线程同步问题>及解决多线程同步互斥的常用方法

秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 本文配套程序下载地址为:http://download.csdn.net/detail/morewindows/5136035 转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8646902 欢迎关注微博:http://weibo.com/MoreWindows 在<秒杀多线程系列>的前十五篇中介绍多线程的相关概念,多线程同步互斥问题<秒杀多

多线程面试题系列(16):多线程十大经典案例之一 双线程读写队列数据

前十五篇中介绍多线程的相关概念,多线程同步互斥问题(第四篇)及解决多线程同步互斥的常用方法--关键段.事件.互斥量.信号量.读写锁.为了让大家更加熟练运用多线程,将会有十篇文章来讲解十个多线程使用案例,相信看完这十篇后会让你能更加游刃有余的使用多线程. 首先来看第一篇--第十六篇 多线程十大经典案例之一 双线程读写队列数据 <多线程十大经典案例之一双线程读写队列数据>案例描述: MFC对话框中一个按钮的响应函数实现两个功能:显示数据同时处理数据,因此开两个线程,一个线程显示数据(开了一个定时器

多线程经典问题2——子线程之间交替问题

编写一个程序.开启3个线程,这3个线程的ID分别为A.B.C,每一个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC-.依次递推. 这个问题仍旧是线程间的交替控制问题,分析方法还是能够同上一篇"多线程经典问题1--主线程子线程交替问题". 详细代码例如以下: package treadgame; /** * 线程间的交流1 * 编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C, * 每一个线程将自己的ID在屏幕上打印10遍, * 要求

网络机器人的识别与攻防的经典案例

本文我们介绍一个网络机器人的识别与攻防的经典案例.使用到的代码见本人的superword项目: https://github.com/ysc/superword/blob/master/src/main/java/org/apdplat/superword/tools/ProxyIp.java 我们的目的是要使用机器人自动获取站点http://ip.qiaodm.com/ 和站点http://proxy.goubanjia.com/ 的免费高速HTTP代理IP和端口号. 不过他们未对机器人进行识

拍卖行与邮件系统——设计者与开发者协作的经典案例

此文仅代表作者本人观点,如有槽点,欢迎吐槽. 设计者与开发者 设计者与开发者,游戏行业内直白的说法就是策划.美术跟程序.但不管在任何行业,这两者之间的关系都既像战友又像敌人.设计者的想法往往是完美的,而开发者的想法却是实际的,就好像梦想与现实一样.我听说过这样的话:美术设计的效果是100%的话,程序呈现出的效果能达到80%就已经很完美了.这当然不是在黑程序,程序出于某些原因无法完全实现效果(资源尺寸,资源通用性,性能考虑等等),毕竟梦想和现实是有差距的.在此案例中,我们仅讨论策划与程序. 拍卖行

(Mirage系列之八)Mirage经典案例之数据更新和恢复

在(Mirage系列之四)Mirage经典案例之集中桌面管理中我们介绍过,Mirage将客户端的数据根据策略备份到服务器上.备份数据的一个最重要的目的就是用户数据恢复,这次我们来讲如何从客户端恢复用户数据. 从客户端恢复用户数据,有以下几种情况: 1.      把文件恢复到以前的某个版本 2.      从存档中恢复文件和文件夹 3.      恢复删除的文件和文件夹 这里,存档指客户端在服务器上的备份.服务器会根据策略按预定的间隔备份客户端数据,从而产生多个存档. 以上三种方式本质上都是一样

(Mirage系列之七)Mirage经典案例之管理和发布应用层

在(Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析中我们介绍过,Mirage从逻辑上把终端桌面分层了三层:系统层(包括驱动和基础层),应用层,以及用户数据层.在(Mirage系列之五)Mirage经典案例之桌面驱动和基础层管理中我们讲到Mirage可以灵活方便的管理终端的驱动并且发布基础层.本文将介绍Mirage如何管理终端的应用层. 一个公司往往有很多部门,各部门所需要的工作软件也不尽相同.Mirage通过分层这个核心技术,将应用层剥离出来,使得管