多线程解题套路

  1. 循环
  2. 同步代码块
  3. 判断共享数据(已经到末尾)
  4. 判断共享数据(没有到末尾)

案例一

需求:
一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,
请用多线程模拟卖票过程并打印剩余电影票的数量

代码实现:

package com.liming.mytest;

public class Test01 {
    /*  需求:
        一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,
        请用多线程模拟卖票过程并打印剩余电影票的数量
        */
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t1.start();
        t2.start();
    }
}

class MyThread extends Thread{
    //第一种方式实现多线程,测试类中MyThread会创建多次,所以需要加static
    static int ticket = 1000;

    @Override
    public void run() {
        //1、循环
        while (true){
            //2、同步代码块
            synchronized (MyThread.class){
                //3、判断共享数据(已经到末尾)
                if (ticket == 0){
                    break;
                }else {
                    //4、判断共享数据(没有到末尾)
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(getName()+"在卖票,还剩"+ticket+"张电影票");
                }
            }
        }
    }
}

案例二

有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。
利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来.

代码实现:

package com.liming.mytest;

public class Test02 {
    public static void main(String[] args) {
        /*
        有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。
        利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来.
        */
        MyRun mr = new MyRun();
        Thread t1 = new Thread(mr,"窗口1");
        Thread t2 = new Thread(mr,"窗口2");
        t1.start();
        t2.start();
    }
}

class MyRun implements Runnable{
    //第二种方式实现多线程,测试类中MyRunable只创建一次,所以不需要加static
    int count = 100;

    @Override
    public void run() {
        //1、循环
        while (true){
            //2、同步代码块
            synchronized (MyRun.class){
                //3、判断共享数据(已经到末尾)
                if (count <= 10){
                    System.out.println("礼物还剩下"+count+"份不在送出");
                    break;
                }else {
                    //4.判断共享数据(没有到末尾)
                    count--;
                    System.out.println(Thread.currentThread().getName() + "在赠送礼物,还剩下" + count + "个礼物!!!");
                }
            }
        }
    }
}

案例三

同时开启两个线程,共同获取1-100之间的所有数字。
输出所有的奇数。

代码实现:

package com.liming.mytest;

public class Test03 {
    public static void main(String[] args) {
        /*同时开启两个线程,共同获取1-100之间的所有数字。
        将输出所有的奇数。*/

        MyRun01 mr = new MyRun01();
        Thread t1 = new Thread(mr,"线程A");
        Thread t2 = new Thread(mr,"线程B");
        t1.start();
        t2.start();
    }
}

class MyRun01 implements Runnable {
    int i = 1;

    @Override
    public void run() {
        //1.循环
        while (i <= 100) {
            //2、同步代码块
            synchronized (MyRun01.class) {
                //3、判断共享数据(已经到末尾)
                if (i > 100) {
                    break;
                } else {
                    //4、判断共享数据(没到末尾)
                    if (i % 2 != 0){
                        System.out.println(Thread.currentThread().getName()+"打印数字"+i);
                    }
                    i++;
                }
            }
        }
    }
}

案例四

假设:100块,分成了3个包,现在有5个人去抢。
其中,红包是共享数据。5个人是5条线程。
打印结果如下:
XXX抢到了XXX元
XXX抢到了XXX元
XXX抢到了XXX元
XXX没抢到
XXX没抢到

代码实现:

package com.liming.mytest;

import java.util.Random;

public class Test04 {
    public static void main(String[] args) {
         /*
    假设:100块,分成了3个包,现在有5个人去抢。
    其中,红包是共享数据。5个人是5条线程。
    打印结果如下:
    XXX抢到了XXX元
    XXX抢到了XXX元
    XXX抢到了XXX元
    XXX没抢到
    XXX没抢到
    */

        //创建线程的对象
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        MyThread t4 = new MyThread();
        MyThread t5 = new MyThread();

        //给线程设置名字
        t1.setName("小A");
        t2.setName("小QQ");
        t3.setName("小哈哈");
        t4.setName("小诗诗");
        t5.setName("小丹丹");

        //启动线程
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

class MyThread01 extends Thread {
    //共享数据,100元,三个红包
    static double money = 100;
    static int count = 3;

    //最小的中奖金额
    static final double MIN = 0.01;

    @Override
    public void run() {
        //同步代码块
        synchronized (MyThread01.class) {
            if (count == 0) {
                //判断共享数据(已经到末尾)
                System.out.println(getName() + "没有抢到红包!");
            } else {
                //判断共享数据(没有到末尾)
                //定义一个变量表示中奖金额
                double prize = 0;
                if (count == 1) {
                    //表示此时是最后一个红包
                    //就无需随机,剩余所有的钱都是中奖金额
                    prize = money;
                } else {
                    //表示第一次,第二次(随机)
                    Random r = new Random();
                    //100 元   3个包
                    //第一个红包:99.98
                    //100 - (3-1) * 0.01
                    double bounds = money - (count - 1) * MIN;//最大中奖金额
                    prize = r.nextDouble(bounds);
                    if (prize < MIN) {
                        prize = MIN;
                    }
                }
                money = money - prize;
                count--;
                System.out.println(getName() + "抢到了:" + prize + "元");
            }
        }
    }
}

案例五

有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1 又产生了一个 10 元大奖
抽奖箱1 又产生了一个 100 元大奖
抽奖箱1 又产生了一个 200 元大奖
抽奖箱1 又产生了一个 800 元大奖
抽奖箱2 又产生了一个 700 元大奖…

代码实现:

package com.liming.mytest;

import java.util.ArrayList;
import java.util.Collections;

public class Test05 {
    public static void main(String[] args) {
        /*需求:
        有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
        创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
        随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
        每次抽出一个奖项就打印一个(随机)
        抽奖箱1 又产生了一个 10 元大奖
        抽奖箱1 又产生了一个 100 元大奖
        抽奖箱1 又产生了一个 200 元大奖
        抽奖箱1 又产生了一个 800 元大奖
        抽奖箱2 又产生了一个 700 元大奖...
         */
        //创建奖池
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);

        //创建线程
        MyThread02 t1 = new MyThread02(list);
        MyThread02 t2 = new MyThread02(list);

        t1.setName("窗口1");
        t2.setName("窗口2");

        //开启线程
        t1.start();
        t2.start();
    }
}

class MyThread02 extends Thread{
    ArrayList<Integer> arrayList;
    public MyThread02(ArrayList<Integer> arrayList){
        this.arrayList = arrayList;
    }

    @Override
    public void run() {
        while (true){
            synchronized (MyThread02.class){
                if (arrayList.size() == 0){
                    break;
                }else {
                    Collections.shuffle(arrayList);
                    int prize = arrayList.remove(0);
                    System.out.println(getName()+"产生了"+prize+"元大奖");
                }
            }
        }
    }
}

案例六

在上一题基础上继续完成如下需求:
每次抽的过程中,不打印,抽完时一次性打印(随机)
在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元
在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元

代码实现:

package com.liming.mytest;

import java.util.ArrayList;
import java.util.Collections;

public class Test06 {
    public static void main(String[] args) {
        /*需求:
        在上一题基础上继续完成如下需求:
        每次抽的过程中,不打印,抽完时一次性打印(随机)
        在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
        分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元
        在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
        分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元*/

        //创建奖池
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);

        //创建线程
        MyThread03 t1 = new MyThread03(list);
        MyThread03 t2 = new MyThread03(list);


        //设置名字
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");


        //启动线程
        t1.start();
        t2.start();
    }
}
class MyThread03 extends Thread{
    ArrayList<Integer> list;

    public MyThread03(ArrayList<Integer> list) {
        this.list = list;
    }

    @Override
    public void run() {
        ArrayList<Integer> boxList = new ArrayList<>();//1 //2
        while (true) {
            synchronized (MyThread.class) {
                if (list.size() == 0) {
                    System.out.println(getName() + boxList);
                    break;
                } else {
                    //继续抽奖
                    Collections.shuffle(list);
                    int prize = list.remove(0);
                    boxList.add(prize);
                }
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}