java多线程练习题

Posted 肖恩雷

tags:

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

java多线程练习题

1. 车站售票

要求: 代码实现火车站3个窗口同时卖25张车票的逻辑,同一个窗口不能卖同一张票

//多线程售票例子
public class TicketDemo {
​
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
   //窗口1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
               ticket.sales();
            }
        },"窗口1").start();
 //窗口2
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                ticket.sales();
            }
        },"窗口2").start();
 //窗口3
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                ticket.sales();
            }
        },"窗口3").start();
    }
​
}
​
/**
*真正的多线程开发记住一句话“线程就是一个单独的资源类,没有任何附属的操作,只有属性和方法”
*/
class  Ticket{
    private int ticketNumber = 25;
​
    public synchronized void sales ()
    {
        if(ticketNumber > 0)
        {
            System.out.println(Thread.currentThread().getName()+"售卖票后,还剩"+ (--ticketNumber) +"张票");
        }else
        {
            System.out.println("票已经销售完了");
        }
    }
​
​
}

 

image-20210623162453702

在<<阿里巴巴java开发手册>>中关于并发控制明确提出必须通过线程池创建,不允许自行显式创建线程和不允许线程池使用Excutors去创建,因此以上的代码是不符合规范的.

image-20210623175623124

因此代码修改成创建线程池,然后从线程池中去获取线程,并且同时自定义线程工厂,可以自定义线程的名称\\组以及优先级等信息,甚至可以任性的将所有的线程设置为守护线程.总之,使用自定义线程池可以让我们更加自由的设置池子中所有线程的状态.

 public class Demo02 {
     
public static void main(String[] args) {
      
        Ticket ticket = new Ticket();
​
        //创建线程池
        ThreadPoolExecutor TicketThreadPool = new ThreadPoolExecutor(
                3, 5, 3, TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(3),
                new NamedThreadFactory("售票ThreadPool"),//默认使用 Executors.defaultThreadFactory()
                new ThreadPoolExecutor.AbortPolicy());
​
        //创建3个线程,每个线程卖10次票
        for (int i = 0; i < 3; i++) {
​
            TicketThreadPool.execute(() -> {
                for (int i1 = 0; i1 < 10; i1++) {
                    ticket.sales();
                }
            });
        }
        //关闭线程池
        TicketThreadPool.shutdown();
    }
}
​
/**
 * 自定义线程工厂
 */
class NamedThreadFactory implements ThreadFactory{
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;
​
    NamedThreadFactory(String name) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        if (null == name || name.isEmpty()) {
            name = "pool";
        }
        namePrefix = name + "-窗口-";
    }
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r, namePrefix + threadNumber.getAndIncrement());
        return thread;
    }
​
}
​
/**
 * 资源类
 */
 class  Ticket  {
    private int ticketNumber = 25;
​
    public synchronized void sales ()
    {
        if(ticketNumber > 0)
        {
            System.out.println(Thread.currentThread().getName()+"售卖票后,还剩"+ (--ticketNumber) +"张票");
        }else
        {
            System.out.println("票已经销售完了");
        }
    }
}

image-20210623182912599

2. 银行存取款

要求:

小明打算去提款机上取钱,发现卡上没有钱,这时候他告知妈妈去存钱,妈妈存了钱了,告知小明存好了可以取钱了。

  • 小明分多次取钱,每次取100,当发现钱不够100,就等妈妈存钱

  • 妈妈每次存钱2000,当发现钱小于100就存钱,并且通知小明取取钱,当大于100就等小明钱不够再存

public class MoneyDemo {
/**
 *要求:
 * (线程通信)小明打算去提款机上取钱,发现卡上没有钱,这时候他告知妈妈去存钱,妈妈存了钱了,告知小明存好了可以取钱了。
 * 小明分多次取钱,每次取100,当发现钱不够100,就等妈妈存钱
 * 妈妈每次存钱2000,当发现钱小于100就存钱,并且通知小明取取钱,当大于100就等小明钱不够再存
 */
    public static void main(String[] args) {
        Money money = new Money();
        //小明取钱
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                money.drawMoney();
            }
            },"小明").start();
​
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                money.storeMoney();
            }
        },"妈妈").start();
    }
}
/*
*资源类
*/
class Money{
​
    private volatile int money = 2000;
​
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
​
    /**
     * 妈妈存钱
     */
    public void storeMoney()
    {
        lock.lock();
        try {
            while (money > 0)
            {
                condition.await();
            }
            this.money = 2000;
            System.out.println("小兔崽子节约点用,老妈又给你打了"+ this.money + "块钱过来");
            condition.signalAll();
​
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
​
    /**
     * 小明取钱
     */
    public void drawMoney()
    {
        lock.lock();
        try {
            while(money > 0)
            {
                money = money - 100;
                System.out.println("小明取款后还剩" + money + "元");
                condition.signalAll();
            }
            condition.await();
        }
          catch (Exception e) {
                e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
​
​
}

image-20210623185330412

这里使用过来JUC里面的Lock锁和Condition来实现线程间的互相通信

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

双线程猜数字 (java多线程习题详述)

双线程猜数字 (java多线程习题详述)

Java 多线程练习

java多线程练习题 类

java--多线程习题练习

java练习多线程