Java 多线程等案例

选择题

题目1(加强训练)

关于同步代码块说法错误的是:()

A: 同步锁对象必须唯一

B: 将要一起同步执行的代码放置到同步锁的代码块中

C: 添加同步代码块增加了程序的效率

D: 添加同步代码块增加程序的安全性

答案:C

解析:同步代码块并没有增加程序效率,反而降低了程序的效率。多线程情况下,遇到同步代码,多个线程会依次进入。

题目2(加强训练)

下列说法错误的是:()

A:多个线程修改同一个数据时,有可能出现错误的操作结果,叫做线程安全问题;
B:线程安全问题发生的需要有多个线程修改同一个数据;
C:要发生线程安全问题,需要多个线程对同一个数据进行修改操作时,CPU可以在不同的线程间来回切换;
D:多个线程操作同一个数据,一定会出现线程安全问题;

答案:D
解析:线程安全问题必须是多个线程对同一个数据发生了修改操作;如果多个线程对同一个数据的操作是读取操作,没有修改操作,则一定不会出现线程安全问题;

题目3(加强训练)

下列说法错误的是:()

A:要避免线程安全问题,应该避免使用多线程;
B:要解决线程安全问题,可以使用同步代码块;
C:使用同步代码块时,必须提供一个锁对象,而且这个锁对象对不同的线程来说,是同一个对象;
D:synchronized修饰非静态方法时,锁对象是调用这个方法的对象;synchronized修饰静态方法时,锁对象是这个方法所在的类;

答案:A
解析:使用多线程是为了程序效率的需求,所以不能通过不使用多线程的方式实现,而是应该使用线程同步技术解决线程安全问题;

编程题

案例1

需求:
实现3个窗口卖票

public class Ticket implements Runnable {
    private Integer count = 100; // 共享数据
    private String lock = new String();
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock) {
            if (count > 0) {
                try {
                    Thread.sleep((int) (Math.random() * 100));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "在卖票,在卖第" + (count--) + "张票!");
            }else{
                break;
            }
        }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Runnable ticket = new Ticket();

        // 创建三个窗口
        Thread t1 = new Thread(ticket,"窗口1");
        Thread t2 = new Thread(ticket,"窗口2");
        Thread t3 = new Thread(ticket,"窗口3");

        //启动
        t1.start();
        t2.start();
        t3.start();
    }
}

案例2

需求:
有100个限量版的水杯,但是只能通过实体店和官网才能进行购买,并且分别统计卖了多少。请用线程进行模拟并设置线程名称用来代表售出途径,再将信息打印出来。比如(实体店卖出第1个,总共剩余n个…)

class Seller implements Runnable {
    // 有100个限量版的水杯
    private int count = 100;
    public void run() {
        // 获取当前线程的名字
        String name = Thread.currentThread().getName();
        // 定义变量统计卖出去的个数
        int sellCount = 0;
        // 开启循环卖票
        while(true) {
            synchronized(this) {
                if(count > 0) {
                    // 每卖出一个count-1
                    count--;
                    // 线程每卖出一个把卖出的数量+1
                    sellCount ++;
                    // 卖出第1个,总共剩余n个.
                    System.out.println(name +"卖出第"+sellCount+"个,总共剩余"+count+"个");
                }else{
                    break;
                }
            }

            // 为了更好看到竞争资源,睡一小下
         /*try {
            Thread.sleep(10);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }*/
        }
    }
}
public class Demo02 {
    public static void main(String[] args) {
        // 创建一个卖水杯的Runnable接口实现类
        Seller seller = new Seller();
        // 创建实体店的线程
        Thread t1 = new Thread(seller, "实体店");
        // 创建官网的线程
        Thread t2 = new Thread(seller,"官网");
        // 实体店开始卖水杯
        t1.start();
        // 官网开始卖水杯
        t2.start();
    }
}

案例3

需求:
使用线程池创建多线程。模拟同学找老师学习Java。

  1. 创建线程池对象,包含2个线程。从线程池中获取线程对象,然后调用MyRunnable中的run()。
  2. 在MyRunnable实现类中,首先在控制台打印需求,“我需要一个老师”。模拟需要2秒钟时间老师可以过来指导学生,并在控制台打印老师的姓名。最后,在控制台打印“教我java,教完后,老师回到了办公室”;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class thread implements Runnable {
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        lock.lock();
        System.out.println("我需要一个老师!");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("我来了" + Thread.currentThread().getName());
        System.out.println("教我java,教完后,老师回到了办公室");
        lock.unlock();
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 1. 创建线程池对象,包含2个线程。从线程池中获取线程对象,然后调用MyRunnable中的run()。
 * 2. 在MyRunnable实现类中,
 * 首先在控制台打印需求,“我需要一个老师”。
 * 模拟需要2秒钟时间老师可以过来指导学生,并在控制台打印老师的姓名。
 * 最后,在控制台打印“教我java,教完后,老师回到了办公室”;
 */
public class Demo {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        thread t = new thread();
        service.submit(t);
        service.submit(t);
        service.shutdown();
    }
}

案例4

需求:

  1. 某公司组织年会,会议入场时有两个入口,在入场时每位员工都能获取一张双色球彩票,假设公司有100个员工, 利用多线程模拟年会入场过程,并分别统计每个入口入场的人数,以及每个员工拿到的彩票的号码。线程运行后打印 格式如下:

    编号为: 2 的员工 从后门 入场! 拿到的双色球彩票号码是:[17, 24, 29, 30, 31, 32, 07] 
    编号为: 1 的员工 从后门 入场! 拿到的双色球彩票号码是:[06, 11, 14, 22, 29, 32, 15] 
    //..... 
    从后门入场的员工总共: 13 位员工 
    从前门入场的员工总共: 87 位员工
    
  2. 题目中用到的产生双色球的工具类已经写好,可以直接使用:

import java.util.Arrays;
import java.util.Random;

public class DoubleColorBallUtil{
    // 产生双色球的代码
    public static String create() {
        String[] red = {"01","02","03","04","05","06","07","08","09","10",
                "11","12","13","14","15","16","17","18","19","20","21","22","23",
                "24","25","26","27","28","29","30","31","32","33"};
        //创建蓝球
        String[] blue = "01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16".split(",");
        boolean[] used = new boolean[red.length];
        Random r = new Random();
        String[] all = new String[7];
        for(int i = 0;i<6;i++) {
            int idx;
            do {
                idx = r.nextInt(red.length);//0‐32
            } while (used[idx]);//如果使用了继续找下一个
            used[idx] = true;//标记使用了
            all[i] = red[idx];//取出一个未使用的红球
        }
        all[all.length-1] = blue[r.nextInt(blue.length)];
        Arrays.sort(all);
        return Arrays.toString(all);
    }
}
public class LuckDraw implements Runnable {
    private int number = 100;

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        int count = 0;
        while (true){
            String s = DoubleColorBallUtil.create();
            synchronized (this) {
                if (number > 0) {
                    System.out.println("编号为:" + number + "的员工 从" + name + " 入场! 拿到的双色球彩票号码是:" + s);
                    number--;
                    count++;
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                        //从后门入场的员工总共: 13 位员工
                    System.out.println("从" + name + "入场的员工总共:" + count + "位员工");
                    break;
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        LuckDraw l = new LuckDraw();
        Thread t1 = new Thread(l,"前门");
        Thread t2 = new Thread(l,"后门");
        t1.start();
        t2.start();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值