zoukankan      html  css  js  c++  java
  • 多线程笔试题

    1、用5个线程去卖火车票,一共5000张,卖完即止。

    用线程池的写法:向线程池提交5000个任务

    public class Test {
        public static void main(String[] args) throws InterruptedException {
            int total = 5000;
            int threadSize = 5;
            TicketHolder ticketHolder = new TicketHolder(total);
            ExecutorService executorService =
                    Executors.newFixedThreadPool(threadSize, new ThreadFactoryBuilder().setNameFormat("线程%d").build());
            for (int i = 1; i <= total; i++) {
                executorService.submit(ticketHolder::decrease);
            }
            executorService.awaitTermination(3, TimeUnit.SECONDS);
            executorService.shutdown();
        }
    }
    
    @Data
    @AllArgsConstructor
    class TicketHolder {
    
        private int total;
    
        public synchronized void decrease() {
            total = total - 1;
            System.out.println(Thread.currentThread().getName() + ",还剩" + total + "张票");
        }
    
    }

    以上代码可以优化下,去掉实体类,而是用静态变量在多个线程间传值:

    用线程池的写法:向线程池提交5个任务

    public class Test {
        public static void main(String[] args) throws InterruptedException {
            int total = 5000;
            int threadSize = 5;
            TicketHolder ticketHolder = new TicketHolder(total);
            ExecutorService executorService =
                    Executors.newFixedThreadPool(threadSize, new ThreadFactoryBuilder().setNameFormat("线程%d").build());
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(1);
                    while (true) {
                        synchronized (this) {
                            if (ticketHolder.getTotal() >= 1) {
                                ticketHolder.decrease();
                            } else {
                                break;
                            }
                        }
                    }
                }
            };
    
            for (int i = 1; i <= threadSize; i++) {
                executorService.submit(runnable);
            }
            executorService.awaitTermination(3, TimeUnit.SECONDS);
            executorService.shutdown();
        }
    }
    
    @Data
    @AllArgsConstructor
    class TicketHolder {
    
        private int total;
    
        public void decrease() {
            total = total - 1;
            System.out.println(Thread.currentThread().getName() + ",还剩" + total + "张票");
        }
    
    }

    不用线程池的写法:

    public class Test {
        public static void main(String[] args) {
            int total = 5000;
            TicketHolder ticketHolder = new TicketHolder(total);
            new Thread(new SellTicketThread(ticketHolder), "线程1").start();
            new Thread(new SellTicketThread(ticketHolder), "线程2").start();
            new Thread(new SellTicketThread(ticketHolder), "线程3").start();
            new Thread(new SellTicketThread(ticketHolder), "线程4").start();
            new Thread(new SellTicketThread(ticketHolder), "线程5").start();
        }
    }
    
    @Data
    @AllArgsConstructor
    class TicketHolder {
    
        private int total;
    
        public void decrease() {
            if (total >= 1) {
                total = total - 1;
                System.out.println(Thread.currentThread() + ",还剩" + total + "张票");
            }
        }
    }
    
    class SellTicketThread implements Runnable {
    
        private final TicketHolder ticketHolder;
    
        @Override
        public void run() {
            while (ticketHolder.getTotal() >= 1) {
                synchronized (ticketHolder) {
                    ticketHolder.decrease();
                }
            }
        }
    
        public SellTicketThread(TicketHolder ticketHolder) {
            this.ticketHolder = ticketHolder;
        }
    }

    2、三个线程,依次打印A、B、C,打印十次,各线程run方法只能执行一次,最后依次输出ABCABCABC...。

    用线程池写法:因为各线程run()方法只能执行一次,所以只能往线程池中提交三个任务。如果提交三十个任务的话,run()方法会执行三十次。

    public class Test {
        public static void main(String[] args) throws InterruptedException {
    
            PrintTime printTime = new PrintTime(0);
    
            ExecutorService executorService =
                    Executors.newFixedThreadPool(3, new ThreadFactoryBuilder().setNameFormat("线程%d").build());
    
    
            Runnable runnableA = () -> {
                for (int i = 1; i <= 10; i++) {
                    synchronized (printTime) {
                        if (printTime.getTime() % 3 == 0) {
                            System.out.print("A");
                            printTime.setTime(printTime.getTime() + 1);
                        } else {
                            i = i - 1;
                        }
                    }
                }
            };
    
            Runnable runnableB = () -> {
                for (int i = 1; i <= 10; i++) {
                    synchronized (printTime) {
                        if (printTime.getTime() % 3 == 1) {
                            System.out.print("B");
                            printTime.setTime(printTime.getTime() + 1);
                        } else {
                            i = i - 1;
                        }
                    }
                }
            };
    
            Runnable runnableC = () -> {
                for (int i = 1; i <= 10; i++) {
                    synchronized (printTime) {
                        if (printTime.getTime() % 3 == 2) {
                            System.out.print("C");
                            printTime.setTime(printTime.getTime() + 1);
                        } else {
                            i = i - 1;
                        }
                    }
                }
            };
    
            executorService.submit(runnableA);
            executorService.submit(runnableB);
            executorService.submit(runnableC);
    
            executorService.awaitTermination(3, TimeUnit.SECONDS);
            executorService.shutdown();
        }
    }
    
    @Data
    @AllArgsConstructor
    class PrintTime {
    
        int time;
    
    }

    不用线程池写法:

    public class Test {
        public static void main(String[] args) {
            PrintTime object = new PrintTime(0);
            new Thread(new PrintThread(object, "A"), "线程1").start();
            new Thread(new PrintThread(object, "B"), "线程2").start();
            new Thread(new PrintThread(object, "C"), "线程3").start();
        }
    }
    
    @Data
    @AllArgsConstructor
    class PrintTime {
        int time;
    }
    
    class PrintThread implements Runnable {
    
        private final PrintTime printTime;
    
        private String printStr;
    
        public PrintThread(PrintTime printTime, String printStr) {
            this.printTime = printTime;
            this.printStr = printStr;
        }
    
        @Override
        public void run() {
            while (true) {
                synchronized (printTime) {
                    if (printTime.getTime() >= 30) {
                        break;
                    }
                    if (("A".equals(printStr) && printTime.getTime() % 3 == 0)
                            || "B".equals(printStr) && printTime.getTime() % 3 == 1
                            || "C".equals(printStr) && printTime.getTime() % 3 == 2
                            ) {
                        System.out.print(printStr);
                        printTime.setTime(printTime.getTime() + 1);
                    }
                }
            }
    
        }
    }

    不用synchronized,用Lock写法:

    public class Test {
        public static void main(String[] args) {
    
            Lock lock = new ReentrantLock();
    
            PrintTime printTime = new PrintTime(0);
    
            new Thread(new ThreadA(lock, printTime), "线程A").start();
            new Thread(new ThreadB(lock, printTime), "线程B").start();
            new Thread(new ThreadC(lock, printTime), "线程C").start();
        }
    }
    
    class ThreadA implements Runnable {
    
        private Lock lock;
    
        private PrintTime printTime;
    
        public ThreadA(Lock lock, PrintTime printTime) {
            this.lock = lock;
            this.printTime = printTime;
        }
    
        @Override
        public void run() {
            int size = 0;
            while (size < 10) {
                if (lock.tryLock()) {
                    try {
                        if (printTime.getTime() % 3 == 0) {
                            size = size + 1;
                            printTime.setTime(printTime.getTime() + 1);
                            System.out.println("A");
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    }
    
    class ThreadB implements Runnable {
    
        private Lock lock;
        private PrintTime printTime;
    
        public ThreadB(Lock lock, PrintTime printTime) {
            this.lock = lock;
            this.printTime = printTime;
        }
    
        @Override
        public void run() {
            int size = 0;
            while (size < 10) {
                if (lock.tryLock()) {
                    try {
                        if (printTime.getTime() % 3 == 1) {
                            size = size + 1;
                            printTime.setTime(printTime.getTime() + 1);
                            System.out.println("B");
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    }
    
    class ThreadC implements Runnable {
    
        private Lock lock;
        private PrintTime printTime;
    
        public ThreadC(Lock lock, PrintTime printTime) {
            this.lock = lock;
            this.printTime = printTime;
        }
    
        @Override
        public void run() {
            int size = 0;
            while (size < 10) {
                if (lock.tryLock()) {
                    try {
                        if (printTime.getTime() % 3 == 2) {
                            size = size + 1;
                            printTime.setTime(printTime.getTime() + 1);
                            System.out.println("C");
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    }
    
    
    @Data
    @AllArgsConstructor
    class PrintTime {
    
        int time;
    
    }

    注意,unlock()方法一定要写在finally块中。

    用wait/notify机制:

    用Condition的await/signal通信机制:

    A线程打印完,唤醒B,且本身await,B线程打印完,唤醒C,且本身await,C线程打印完,唤醒A,且本身await。。。依次

    public class AwaitSignalTest {
    
        public static void main(String[] args) {
            Lock lock = new ReentrantLock();
            Condition conditionA = lock.newCondition();
            Condition conditionB = lock.newCondition();
            Condition conditionC = lock.newCondition();
    
            int threadSize = 3;
            int printTimePerThread = 10;
            int maxPrintTime = threadSize * printTimePerThread;
    
            new Thread(new Print(lock, conditionA, conditionB, "A", threadSize, maxPrintTime, 0)).start();
            new Thread(new Print(lock, conditionB, conditionC, "B", threadSize, maxPrintTime, 1)).start();
            new Thread(new Print(lock, conditionC, conditionA, "C", threadSize, maxPrintTime, 2)).start();
    
        }
    
    }
    
    class Print implements Runnable {
    
        private static int printTimeInt = 0;
    
        private Lock lock;
        private final Condition conditionToWait;
        private final Condition conditionNotify;
    
        private String printStr;
        private int threadSize;
        private int maxPrintTime;
        private int index;
    
        public Print(Lock lock, Condition conditionToWait, Condition conditionNotify, String printStr,
                int threadSize, int maxPrintTime, int index) {
            this.lock = lock;
            this.conditionToWait = conditionToWait;
            this.conditionNotify = conditionNotify;
            this.printStr = printStr;
            this.threadSize = threadSize;
            this.maxPrintTime = maxPrintTime;
            this.index = index;
        }
    
        @Override
        public void run() {
            while (true) {
                lock.lock();
                if (printTimeInt >= maxPrintTime) {
                    System.exit(1);
                }
                if (printTimeInt % threadSize == index) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(printStr);
                    printTimeInt++;
                    conditionNotify.signal();
                }
                try {
                    conditionToWait.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    上面的代码不是一次写好的,是先把三个线程的实现分别写出来,调通,然后一步步调优得到的。代码中的System.exit(1);是让jvm退出,自己习惯是lock.unlock();break;,但是这样不行,原因还没定位出来。

    一个Lock实例可以生成多个Condition实例,而调用任意一个Condition实例的await()方法都会使调用线程释放掉这个Lock实例,如果在await之前先调用另一个Condition实例的signal()方法,则相当于先唤醒另一个线程,然后让本线程等待唤醒。这样的特性非常适合于多线程中各线程按照自定义顺序执行的场景,但是编程难度也是很大的,要debug好久。

  • 相关阅读:
    剑指Offer
    剑指Offer
    ASP.NET MVC4中的bundles特性引发服务器拒绝访问(403错误)
    less文件的样式无法生效的一个原因,通过WEB浏览器访问服务器less文件地址返回404错误
    Sqlserver Sql Agent Job 只能同时有一个实例运行
    SSAS 聚合设计提升CUBE的查询性能(转载)
    SQL SERVER: 合并相关操作(Union,Except,Intersect)
    SQL Server安装完成后3个需要立即修改的配置选项(转载)
    收缩TempDB的办法(转载)
    SSIS 关于并发的两个设置
  • 原文地址:https://www.cnblogs.com/koushr/p/5873423.html
Copyright © 2011-2022 走看看