多线程综合练习

练习一:售票

需求:

         一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为30毫秒,

         请用多线程模拟卖票过程并打印剩余电影票的数量。

package com.gch.d13_my_thread_test.test1;

public class MyThread extends Thread{
    /**
     * 调用父类的有参构造器
     * @param name:线程名
     */
    public MyThread(String name){
        super(name);
    }
    // 第一种方式实现多线程,测试类中MyThread会创建多次,所以需要加static
    public static int ticket = 0; // 0 ~ 999
    @Override
    public void run() {
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyThread.class){
                // 3.判断共享数据是否已经到了末尾(到了末尾)
                if(ticket == 1000){
                    break;
                }else{
                    // 4.判断共享数据是否已经到了末尾(没有到末尾,执行核心逻辑)
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    ticket++;
                    System.out.println(getName() + "卖出了第" + ticket + "张电影票,剩余"
                            + (1000 - ticket) + "张电影票!");
                }

            }
        }
    }
}
package com.gch.d13_my_thread_test.test1;

/*
### 练习一:售票

需求:

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

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

 

练习二:赠送礼物

需求:

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

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

package com.gch.d13_my_thread_test.test2;

public class MyThread extends Thread{
    /**
     * 调用父类的有参构造器
     * @param name:线程名
     */
    public MyThread(String name) {
        super(name);
    }
    // 由于测试类MyThread将会被创建多次,所以加static,表示本类的所有对象都共享该变量
    public static int gifts = 100;

    @Override
    public void run() {
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyThread.class){
                // 3.判断共享数据是否已经到了末尾(到了末尾)
                if(gifts == 9){
                    System.out.println("只剩" + gifts + "份礼品了,不再送出!");
                    break;
                }else{
                    // 4.判断共享数据是否已经到了末尾(没有到末尾,执行核心逻辑)
                    gifts--;
                    System.out.println(getName() + "正在发送第" + (100 - gifts) + "份礼品,还剩余" + gifts + "份礼品!");
                }

            }
        }
    }
}
package com.gch.d13_my_thread_test.test2;

/*
   ### 练习二:赠送礼物

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

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

练习三:打印数字

需求:

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

         将输出所有的奇数。

package com.gch.d13_my_thread_test.test3;

/**
   线程任务类
 */
public class MyRunnable implements Runnable {
    // 第二种方式实现多线程,由于测试类中MyRunnable只创建一次,所以不需要加static
    public int number = 1;
    @Override
    public void run() {
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyRunnable.class){
                // 3.判断共享数据是否已经到达末尾
                if(number > 100){
                    break;
                }else{
                    // 4.判断共享数据是否已经到达末尾(如果没有到,执行核心逻辑)
                    if(number % 2 == 1){
                        System.out.println(Thread.currentThread().getName() + "打印输出:" + number);
                    }
                    number++;
                }
            }
        }
    }
}
package com.gch.d13_my_thread_test.test3;

/*
   ### 练习三:打印数字

需求:
	同时开启两个线程,共同获取1-100之间的所有数字。
    将输出所有的奇数。
 */
public class ThreadDemo {
    public static void main(String[] args) {
        // 1.创建线程任务类对象
        Runnable target = new MyRunnable();

        // 2.创建线程对象
        Thread t1 = new Thread(target,"线程1");
        Thread t2 = new Thread(target,"线程2");

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

 练习四:抽奖箱

需求:

有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {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.gch.d13_my_thread_test.test5;

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

public class MyThread extends Thread {
    // 共享数据
    // {10,5,20,50,100,200,500,800,2,80,300,700}
    // 集合
    List<Integer> list;
    
    /**
     * 有参构造器
     * @param name:线程名
     * @param list:奖池集合
     */
    public MyThread(String name, List<Integer> list) {
        super(name);
        this.list = list;
    }

    @Override
    public void run() {
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyThread.class){
                // 3.判断共享数据是否已经到了末尾(到了末尾)
                if(list.size() == 0){
                    break;
                }else{
                    // 4.判断共享数据是否已经到了末尾(没有到末尾,执行核心逻辑)
                    // 继续抽奖
                    Collections.shuffle(list);
                    int prize = list.remove(0);
//                    Integer i = list.get(0);
//                    list.remove(0);
                    System.out.println(getName() + "又产生了一个" + prize + "元的大奖!");
                }
            }
            // 把线程睡眠写在锁的外面,因为写在里面其他线程也进不来啊
            try {
                Thread.sleep(20);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
package com.gch.d13_my_thread_test.test5;

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

/*
  需求:

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

每次抽出一个奖项就打印一个(随机):
		抽奖箱1 又产生了一个 10 元大奖
  		抽奖箱1 又产生了一个 100 元大奖
  		抽奖箱1 又产生了一个 200 元大奖
  		抽奖箱1 又产生了一个 800 元大奖
		抽奖箱2 又产生了一个 700 元大奖
 */
public class ThreadTest {
    public static void main(String[] args) {
        // 1.创建奖池
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
        System.out.println(list.size()); // 12

        // 2.创建线程对象
        Thread t1 = new MyThread("抽奖箱1",list);
        Thread t2 = new MyThread("抽奖箱2",list);

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

 练习五:

需求:
       有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为                             {10,5,20,50,100,200,500,800,2,80,300,700};
       创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
       随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
       每次抽的过程中,不打印,抽完时一次性打印(随机),在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
       分别为:10,20,100,500,2,300最高奖项为300元,总金额为932元
       在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
       分别为:5,50,200,800,80,700最高奖项为800元,总金额为1835元
package com.gch.d13_my_thread_test.test6;

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

public class MyThread extends Thread {
    // 共享数据
    // {10,5,20,50,100,200,500,800,2,80,300,700}
    // 集合
    List<Integer> list;
    /**
     * 有参构造器
     * @param name:线程名
     * @param list:奖池集合
     */
    public MyThread(String name, List<Integer> list) {
        super(name);
        this.list = list;
    }
    // 线程1:抽奖箱1
    public static List<Integer> list1 = new ArrayList<>();
    // 线程2:抽奖箱2
    public static List<Integer> list2 = new ArrayList<>();

    @Override
    public void run() {
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyThread.class){
                // 3.判断共享数据是否已经到了末尾(到了末尾)
                if(list.size() == 0){
                    // 表示抽奖结束
                    // 遍历求和
                    int sum1 = 0; // 用于记录抽奖箱1的总金额
                    for (int i = 0; i < list1.size(); i++) {
                        sum1 += list1.get(i);
                    }
                    int sum2 = 0; // 用于记录抽奖箱2的总金额
                    for (int i = 0; i < list2.size(); i++) {
                        sum2 += list2.get(i);
                    }

                    if("抽奖箱1".equals(getName())){
                        System.out.println("抽奖箱1:" + list1 + "  最高奖项为:" + Collections.max(list1) + "元,总金额为:" + sum1 + "元!");
                    }else{
                        System.out.println("抽奖箱2:" + list2 + "  最高奖项为:" + Collections.max(list2) + "元,总金额为:" + sum2 + "元!");
                    }
                    break;
                }else{
                    // 4.判断共享数据是否已经到了末尾(没有到末尾,执行核心逻辑)
                    // 继续抽奖
                    Collections.shuffle(list);
                    int prize = list.remove(0);
                    if("抽奖箱1".equals(getName())){
                        list1.add(prize);
                    }else{
                        list2.add(prize);
                    }
                }
            }
            // 把线程睡眠写在锁的外面,因为写在里面其他线程也进不来啊
            try {
                Thread.sleep(20);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
package com.gch.d13_my_thread_test.test6;


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

/*需求:
       有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
       创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
       随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
       每次抽的过程中,不打印,抽完时一次性打印(随机)    在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
       分别为:10,20,100,500,2,300最高奖项为300元,总金额为932元
       在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
       分别为:5,50,200,800,80,700最高奖项为800元,总金额为1835元
      */
public class ThreadTest {
    public static void main(String[] args) {
        // 1.创建奖池
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
        System.out.println(list.size()); // 12

        // 2.创建线程对象
        Thread t1 = new MyThread("抽奖箱1",list);
        Thread t2 = new MyThread("抽奖箱2",list);

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

 ....练习5代码改进:线程栈

线程栈:

  • 在Java内存图当中,堆内存它是唯一的而栈内存它不是唯一的,它是跟线程是有关系的,简单理解就是每一个线程都有自己的栈,所以说,我们一般把它称为线程栈
  • 在没有学多线程之前,所画的栈内存图都是main线程的栈,而程序的主入口main方法就是运行在main线程这个栈当中的
  • 每一个线程都有自己独立的栈空间

线程栈内存图:

 

package com.gch.d13_my_thread_test.test6_;

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

public class MyThread extends Thread {
    // 共享数据
    // {10,5,20,50,100,200,500,800,2,80,300,700}
    // 集合
    List<Integer> list;
    /**
     * 有参构造器
     * @param name:线程名
     * @param list:奖池集合
     */
    public MyThread(String name, List<Integer> list) {
        super(name);
        this.list = list;
    }

    @Override
    public void run() {
        // 创建每个线程抽中奖项的集合
        // 线程栈
        List<Integer> boxList = new ArrayList<>();
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyThread.class){
                // 3.判断共享数据是否已经到了末尾(到了末尾)
                if(list.size() == 0){
                    // 表示抽奖结束
                    int sum = 0; // 记录每个线程抽中奖项的综合
                    for (int i = 0; i < boxList.size(); i++) {
                        sum += boxList.get(i);
                    }
                    System.out.println(getName() + ":" + boxList + " , 最高奖项为:" + Collections.max(boxList)
                            + "元,总金额为:" + sum + "元!");
                    break;
                }else{
                    // 4.判断共享数据是否已经到了末尾(没有到末尾,执行核心逻辑)
                    // 继续抽奖
                    Collections.shuffle(list);
                    int prize = list.remove(0);
                    boxList.add(prize);
                }
            }
            // 把线程睡眠写在锁的外面,因为写在里面其他线程也进不来啊
            try {
                Thread.sleep(20);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
package com.gch.d13_my_thread_test.test6_;


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

/*需求:
       有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
       创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
       随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
       每次抽的过程中,不打印,抽完时一次性打印(随机)    在此次抽奖过程中,抽奖箱1总共产生了6个奖项。
       分别为:10,20,100,500,2,300最高奖项为300元,总金额为932元
       在此次抽奖过程中,抽奖箱2总共产生了6个奖项。
       分别为:5,50,200,800,80,700最高奖项为800元,总金额为1835元
      */
public class ThreadTest {
    public static void main(String[] args) {
        // 1.创建奖池
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
        System.out.println(list.size()); // 12

        // 2.创建线程对象
        Thread t1 = new MyThread("抽奖箱1",list);
        Thread t2 = new MyThread("抽奖箱2",list);
        Thread t3 = new MyThread("抽奖箱3",list);
        Thread t4 = new MyThread("抽奖箱4",list);

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

 

package com.gch.d13_my_thread_test.test7;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    // 共享数据
    // {10,5,20,50,100,200,500,800,2,80,300,700}
    // 集合
    List<Integer> list;
    /**
     * 有参构造器
     * @param list:奖池集合
     */
    public MyCallable(List<Integer> list) {
        this.list = list;
    }
    
    @Override
    public Integer call() throws Exception {
        // 创建每个线程抽中奖项的集合
        // 线程栈
        List<Integer> boxList = new ArrayList<>();
        // 1.循环
        while(true){
            // 2.同步代码块
            synchronized(MyCallable.class){
                // 3.判断共享数据是否已经到了末尾(到了末尾)
                if(list.size() == 0){
                    // 表示抽奖结束
                    int sum = 0; // 记录每个线程抽中奖项的综合
                    for (int i = 0; i < boxList.size(); i++) {
                        sum += boxList.get(i);
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + boxList + " , 最高奖项为:" + Collections.max(boxList)
                            + "元,总金额为:" + sum + "元!");
                    break;
                }else{
                    // 4.判断共享数据是否已经到了末尾(没有到末尾,执行核心逻辑)
                    // 继续抽奖
                    Collections.shuffle(list);
                    int prize = list.remove(0);
                    boxList.add(prize);
                }
            }
            // 把线程睡眠写在锁的外面,因为写在里面其他线程也进不来啊
            try {
                Thread.sleep(20);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 把集合的最大值返回
        if(boxList.size() == 0){
            // 表示当前线程一个奖都没抽到
            return null;
        }else{
            return Collections.max(boxList);
        }
    }
}
package com.gch.d13_my_thread_test.test7;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadTest {
    public static void main(String[] args) throws Exception {
         /*
            有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
            创建两个抽奖箱(线程)设置线程名称分别为    "抽奖箱1", "抽奖箱2"
            随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:

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

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

            在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元
            核心逻辑:获取线程抽奖的最大值(看成是线程运行的结果)
            说白了就是获取两条线程的最大值


            以上打印效果只是数据模拟,实际代码运行的效果会有差异
        */
        // 1.创建奖池
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
        System.out.println(list.size()); // 12

        // 2.创建MyCallable任务对象,创建多线程要运行的参数对象
        Callable<Integer> call = new MyCallable(list);

        // 3.把Callable任务对象交给FutureTask对象作为线程任务对象
        // 创建多线程要运行的管理者对象
        // 线程一
        FutureTask<Integer> ft1 = new FutureTask<>(call);
        // 线程二
        FutureTask<Integer> ft2 = new FutureTask<>(call);

//        FutureTask<Integer> ft1 = new FutureTask<>(new MyCallable(list));
//        FutureTask<Integer> ft2 = new FutureTask<>(new MyCallable(list));

        // 4.创建线程对象
        Thread t1 = new Thread(ft1,"抽奖箱1");
        Thread t2 = new Thread(ft2,"抽奖箱2");

        // 5.启动线程
        t1.start();
        t2.start();

//        Integer max1 = ft1.get();
//        Integer max2 = ft2.get();
        System.out.println("抽奖池1最高奖项:" + ft1.get());
        System.out.println("抽奖池2最高奖项:" + ft2.get());
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Surpass余sheng军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值