RuiCode

  • 首页
  • 归档

  • 搜索
操作系统 并发 排序 网络 源码分析 二分法 面试 不重复算法 指针移动 java 算法 mysql Linux

【面试经】多线程控制输出1

发表于 2020-02-29 | 分类于 面试经 | 2 | 阅读次数 385
  1. 题目要求
  • 3个线程打印1-100的整数,每个线程打印3个数字,结果要求是有序输出 线程1:1,2,3,... 线程2:4,5,6,... 线程3:7,8,9
  1. 很ugly的思路
  • 创建三个线程,每个线程依赖一个信号量,并在处理完之后释放下一个信号量,实现线程之间的同步
  • 线程内部一直循环,直到某一线程到达指定的数字,直接调用System.exit(0),退出JVM虚拟机
  • 缺点:可扩展性差,如果要增加线程数,还要多加Semaphore和run方法代码
package com.example.demo;
import java.util.concurrent.Semaphore;

public class PrintNum {
    static int num = 0;
    static int i=1;

    public static void main(String[] args) {
        num = 100;
        Semaphore semaphore1 = new Semaphore(1);
        Semaphore semaphore2 = new Semaphore(0);
        Semaphore semaphore3 = new Semaphore(0);
        new Thread(()->{
            while (true){
                try {
                    semaphore1.acquire();
                    printTask();
                    semaphore2.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()->{
            while (true){
                try {
                    semaphore2.acquire();
                    printTask();
                    semaphore3.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()->{
            while (true){
                try {
                    semaphore3.acquire();
                    printTask();
                    semaphore1.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    static void printTask() {
        System.out.print(Thread.currentThread().getName()+": ");
        int count = 0;
        while(count <=2) {
            System.out.print(i++ + " ");
            if(i == num+1) {
                System.exit(0);
            }
            count++;
        }
        System.out.println();
    }
}

image.png

  1. 改进思路
  • 使用固定的线程池
  • 创建一个记录线程的数组列表,当第一次运行的时候将该线程添加到列表中,然后使用自旋,直到轮到自己在数组中的index号,再执行任务
  • 优点:可以指定任意个线程大小
  • 缺点:使用数组,自己建立同步关系,代码不易懂~
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PrintNum {
    static int threadNum = 5; // 有几个线程执行
    static int num = 100;  // 数的最大值
    static int currPrintNum = 1; // 当前输出的数
    static List<Thread> threadList; // 顺序存储Thread的列表
    static int currThreadIndex = 0;  // 一个指向需要执行的Thread的指针
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
        threadList= new ArrayList<>();
        for(int i = 0; i < threadNum ;i++) {
            executorService.execute(new PrintRunnable());
        }
    }

    static class PrintRunnable implements Runnable {
        @Override
        public void run() {
            Thread currThread = Thread.currentThread();
            if(!threadList.contains(currThread)) {
                synchronized (PrintRunnable.class) { // 使用类锁
                    currThread.setName("线程" + (currThreadIndex+1));
                    threadList.add(currThread);
                    myTask();
                    if(threadNum-1 == currThreadIndex) {
                        currThreadIndex = 0;
                    } else {
                        currThreadIndex++;
                    }
                }
            }
            while(true) { // myTask() 调用System.exit() 所有的线程结束循环
		// 使用自旋
                while( threadList.indexOf(currThread) != currThreadIndex) {
                }
                synchronized (PrintRunnable.class) {
                    myTask();
                    if(threadNum-1 == currThreadIndex) {
                        currThreadIndex = 0;
                    } else {
                        currThreadIndex++;
                    }
                }
            }
        }
    }

    static void myTask() {
        System.out.print(Thread.currentThread().getName()+": ");
        int count = 0;
        while(count <=2) {
            System.out.print(currPrintNum++ + " ");
            if(currPrintNum == num+1) {
                System.exit(0);
            }
            count++;
        }
        System.out.println();
    }
}

image.png

  • 本文作者: RuiCode
  • 本文链接: https://www.ruicode.cn/archives/面试经多线程控制输出1
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 操作系统 # 并发 # 排序 # 网络 # 源码分析 # 二分法 # 面试 # 不重复算法 # 指针移动 # java # 算法 # mysql # Linux
【面试经】操作系统内存管理2 -- 虚拟内存、请求分页
  • 文章目录
  • 站点概览
RuiCode

RuiCode

19 日志
5 分类
13 标签
Creative Commons
© 2021 RuiCode
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4

冀公网安备 13050002001906号