多线程练习

练习一:售票

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

多个线程操作共享数据。

线程类:

public class ThreadDemo1 extends Thread{
    static int ticket = 1000;
    @Override
    public void run() {
        while (true) {
            synchronized (ThreadDemo1.class) {
                if (ticket == 0) {
                    break;
                }
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                ticket--;
                System.out.println("剩余" + ticket + "张电影票");
            }
        }
    }
}

 测试类:

public class Test1 {
    public static void main(String[] args) {
        ThreadDemo1 t1 = new ThreadDemo1();
        ThreadDemo1 t2 = new ThreadDemo1();
        t1.setName("窗口一");
        t2.setName("窗口二");
        t1.start();
        t2.start();
    }
}

练习二:赠送礼物

需求:有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。

利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来。

线程类:

public class ThreadDemo2 extends Thread{
    static int ticket = 100;
    @Override
    public void run() {
        while (true)
            synchronized (ThreadDemo2.class) {
                if (ticket < 10) {
                    break;
                }
                ticket--;
                System.out.println(this.getName() + ":剩余" + ticket + "份礼物");
            }
    }
}

 测试类: 

public class Test2 {
    public static void main(String[] args) {
        ThreadDemo2 t1 = new ThreadDemo2();
        ThreadDemo2 t2 = new ThreadDemo2();
        t1.setName("小刘");
        t2.setName("小张");
        t1.start();
        t2.start();
    }
}

练习三:打印数字

需求:同时开启两个线程,共同获取1-100之间的所有数字。

将输出所有的奇数。

线程类:

public class ThreadDemo3 extends Thread{
    static int number = 1;

    @Override
    public void run() {
        while (true) {
            synchronized (ThreadDemo3.class) {
                if (number > 100) {
                    break;
                }
                if (number % 2 != 0) {
                    System.out.println(number);
                }
                number++;
            }
        }
    }
}

 测试类: 

public class Test3 {
    public static void main(String[] args) {
        ThreadDemo3 t1 = new ThreadDemo3();
        ThreadDemo3 t2 = new ThreadDemo3();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

练习四:抢红包

需求:

抢红包也用到了多线程。

假设:100块,分成了3个包,现在有5个人去抢。

其中,红包是共享数据。

5个人是5条线程。

打印结果如下:

XXX抢到了XXX元

XXX抢到了XXX元

XXX抢到了XXX元

XXX没抢到

XXX没抢到

线程类:

import java.util.Random;

public class ThreadDemo4 extends Thread {
    // 总钱数
    static int totalMoney = 100;
    // 3个人抢到红包
    static int count = 1;
    final int MIN = 1;

    @Override
    public void run() {
        synchronized (ThreadDemo4.class) {
            // 3个红包已抢完
            if (count == 4) {
                System.out.println(this.getName() + "没抢到");
            }
            // 第3个红包直接就是剩下的钱
            if (count == 3) {
                System.out.println(this.getName() + "抢了" + totalMoney + "元");
                count++;
            }
            if (count <= 2) {
                Random r = new Random();
                int money = r.nextInt(totalMoney - MIN * (3 - count)) + MIN;
                System.out.println(this.getName() + "抢了" + money + "元");
                totalMoney -= money;
                count++;
            }
        }
    }
}

关于此题,每个线程的run方法只执行一次,如何保证每个线程只抽一次?因为抽完线程就die了,不会再运行了。Java中线程的6个状态。

练习五:抽奖箱

需求:

有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};

创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”。

随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:

每次抽出一个奖项就打印一个(随机)

抽奖箱1 又产生了一个 10 元大奖

抽奖箱1 又产生了一个 100 元大奖

抽奖箱1 又产生了一个 200 元大奖

抽奖箱1 又产生了一个 800 元大奖  

抽奖箱2 又产生了一个 700 元大奖

将奖项放在集合中。随机获取索引,而集合中有一个remove方法在依据索引删除元素时会将删除的元素进行返回。或者利用工具类Collections的shuffle方法打乱元素,然后也是利用remove删除0索引处的元素并进行返回。

线程类:

import java.util.ArrayList;
import java.util.Random;

public class ThreadDemo5 extends Thread {
    ArrayList<String> list;

    public ThreadDemo5(ArrayList<String> list) {
        this.list = list;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (ThreadDemo5.class) {
                int length = list.size();
                if (length == 0) {
                    break;
                }
                Random r = new Random();
                int index = r.nextInt(length);
                System.out.println(this.getName() + "又产生了一个"+list.remove(index)+"元大奖");
            }
        }
    }
}
public class Test5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "10", "5", "20", "50", "100", "200", "500", "800", "2", "80", "300", "700");
        ThreadDemo5 t1 = new ThreadDemo5(list);
        ThreadDemo5 t2 = new ThreadDemo5(list);
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
        t1.start();
        t2.start();
    }
}

练习六:多线程统计并求最大值

需求:

在上一题基础上继续完成如下需求:

每次抽的过程中,不打印,抽完时一次性打印(随机)

在此次抽奖过程中,抽奖箱1总共产生了6个奖项。

分别为:10,20,100,500,2,300,最高奖项为300元,总计额为932元。

在此次抽奖过程中,抽奖箱2总共产生了6个奖项。

分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。

为每个线程单独定义一个集合存自己抽到的奖。 

线程类: 

import java.util.ArrayList;
import java.util.Random;

public class ThreadDemo6 extends Thread {
    ArrayList<Integer> list;

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

    @Override
    public void run() {
        ArrayList<Integer> list1 = new ArrayList<>();
        while (true) {
            synchronized (ThreadDemo6.class) {
                int length = list.size();
                if (length == 0) {
                    int max = 0, sum = 0;
                    for (Integer prize : list1) {
                        sum += prize;
                        if (prize > max) {
                            max = prize;
                        }
                    }
                    System.out.println("此次抽奖过程中," + this.getName() + "总共产生了" + list1.size() + "个奖项。");
                    System.out.print("分别为:");
                    for (Integer i : list1) {
                        System.out.print(i + ",");
                    }
                    System.out.println("最高奖项为" + max + "元,总计金额为" + sum + "元");
                    break;
                }
                Random r = new Random();
                int index = r.nextInt(length);
                list1.add(list.remove(index));
            }
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

 测试类:

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

public class Test6 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list, 10,5,20,50,100,200,500,800,2,80,300,700);
        ThreadDemo6 t1 = new ThreadDemo6(list);
        ThreadDemo6 t2 = new ThreadDemo6(list);
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
        t1.start();
        t2.start();
    }
}

练习七:多线程之间的比较

需求:

在上一题基础上继续完成如下需求:

在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300

最高奖项为300元,总计额为932元。

在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700

最高奖项为800元,总计额为1835元。

在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元

以上打印效果只是数据模拟,实际代码运行的效果会有差异

在测试类中将最大奖项获取出来再传递给每一个线程,当每一个线程抽取结束之后,将自己抽的最大值与最大奖项的值进行比较,如果相等则进行输出。

import java.util.ArrayList;
import java.util.Random;

public class ThreadDemo7 extends Thread {
    ArrayList<Integer> list;
    int maxPrize;

    public ThreadDemo7(ArrayList<Integer> list, int maxPrize) {
        this.list = list;
        this.maxPrize = maxPrize;
    }

    @Override
    public void run() {
        ArrayList<Integer> list1 = new ArrayList<>();
        while (true) {
            synchronized (ThreadDemo7.class) {
                int length = list.size();
                if (length == 0) {
                    int max = 0, sum = 0;
                    for (Integer prize : list1) {
                        sum += prize;
                        if (prize > max) {
                            max = prize;
                        }
                    }
                    System.out.println("此次抽奖过程中," + this.getName() + "总共产生了" + list1.size() + "个奖项。");
                    System.out.print("分别为:");
                    for (Integer i : list1) {
                        System.out.print(i + ",");
                    }
                    System.out.println("最高奖项为" + max + "元,总计金额为" + sum + "元");
                    if (max == maxPrize) {
                        System.out.println("在此次抽奖过程中," + this.getName() + "中产生了最大奖项,该奖项金额为" +max +"元");
                    }
                    break;
                }
                Random r = new Random();
                int index = r.nextInt(length);
                list1.add(list.remove(index));
            }
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

测试类:

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

public class Test7 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
        int maxPrize = 0;
        for (Integer i : list) {
            if (i > maxPrize) {
                maxPrize = i;
            }
        }
        ThreadDemo7 t1 = new ThreadDemo7(list, maxPrize);
        ThreadDemo7 t2 = new ThreadDemo7(list,maxPrize);
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");
        t1.start();
        t2.start();
    }
}

还可以利用线程的抵第3种创建方式,将结果进行返回。

public class MyCallable implements Callable<Integer> {

    ArrayList<Integer> list;

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

    @Override
    public Integer call() throws Exception {
        ArrayList<Integer> boxList = new ArrayList<>();//1 //2
        while (true) {
            synchronized (MyCallable.class) {
                if (list.size() == 0) {
                    System.out.println(Thread.currentThread().getName() + boxList);
                    break;
                } else {
                    //继续抽奖
                    Collections.shuffle(list);
                    int prize = list.remove(0);
                    boxList.add(prize);
                }
            }
            Thread.sleep(10);
        }
        //把集合中的最大值返回
        if(boxList.size() == 0){
            return null;
        }else{
            return Collections.max(boxList);
        }
    }
}

  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值