多线程经典案例

Posted aikf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程经典案例相关的知识,希望对你有一定的参考价值。

售票服务

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("出票失败,位置不够");
            }
        }
    }
}

 

以上是关于多线程经典案例的主要内容,如果未能解决你的问题,请参考以下文章

多线程 Thread 线程同步 synchronized

多个用户访问同一段代码

线程学习知识点总结

多个请求是多线程吗

java多线程轮流打印数字字母案例代码

Java多线程:线程同步详解