如何控制线程并发数,如何使用信号池和线程池?

如何控制线程并发数

(1)如果我们想要控制同步问题,我们可以有很多种解决办法,最常见的一种是使用synchronized关键字,相当于一个进入之后锁住,然后出来之后解锁。一个一个进出。
(2)如果我们想要控制线程并发数为5,可以有5个线程同时执行该如何做?
在java中我们使用信号池Semaphore
在Android中使用线程池Executor来设定。可以使用android已封装的API,也可以使用自定义的线程池。

代码如下

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for(int i=0;i<20;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        test();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                }
            }).start();
        }

    }
  private void test(){
        System.out.println(Thread.currentThread().getName()+"进来了");

        count ++;

        System.out.println(Thread.currentThread().getName()+"出去了");

    }

像这样的万军齐发的多线程该如何控制线程并发数?
在Java中,控制同时执行的线程数最多为3个

 Semaphore sp = new Semaphore(3);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for(int i=0;i<20;i++){

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {

                            sp.acquire();
                            Thread.sleep(2000);
                            test();
                             sp.release();


                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                }
            }).start();
        }

    }
  private void test(){
        System.out.println(Thread.currentThread().getName()+"进来了");

        count ++;

        System.out.println(Thread.currentThread().getName()+"出去了");

    }

在android中,解决办法如下使用Executors,是已经封装好了的各种的线程池。

ExecutorService tt = Executors.newCachedThreadPool();

ExecutorService ta = Executors.newScheduledThreadPool(3, new ThreadFactory() {
     @Override
     public Thread newThread(@NonNull Runnable r) {
         return null;
     }
 });

 ExecutorService tss = Executors.newFixedThreadPool(2, new ThreadFactory() {
     @Override
     public Thread newThread(@NonNull Runnable r) {
         return null;
     }
 });

而真正的线程池管理者为ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize, 线程池中核心线程数
        int maximumPoolSize, 线程池中最大线程数量
        long keepAliveTime, 多余空闲线程的存活时间
        TimeUnit unit,时间单位
        BlockingQueue<Runnable> workQueue) { 任务队列,存储已提交但未被执行的任务

        }

线程池的管理原理:
线程池按以下行为执行任务
aa . 当线程数小于核心线程数时,创建线程。
bb . 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
cc . 当线程数大于等于核心线程数,且任务队列已满时
若线程数小于最大线程数,创建线程
若线程数等于最大线程数,抛出异常,拒绝任务
例如核心线程数corePoolSize=5;maxPoolSize = 10;workQueue = 100;
(1)如果有4个任务,则开启4个线程,4个线程都执行
(2)如果有6个任务,则开启6个线程,5个线程执行,1个线程放入队列中等待
(3)如果有106个任务,则开启106个线程,5个线程执行,100个线程在队列中等待,线程池创建新的线程执行1个任务
(4)如果有111个任务,则开启111个线程,10个线程执行,100个等待,总任务数超出要抛出异常。

自定义线程池
(1)依据原则

 创建线程池是需要资源的,所以线程池内线程数量的大小会影响系统的性能
      大了会浪费资源,小了影响系统的吞吐量
      所以创建线程池需要原则

      需要考虑的因素有CPU的数量,内存大小,并发请求的数量
      通常核心线程数可以设为CPU数量+1,而最大线程设为CPU数量+2+1

(2)具体代码

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //获取CPU的数量
        final int cpu = Runtime.getRuntime().availableProcessors();

        //设定线程池中的核心线程数
        final int corePoolSize = cpu +1;

        //设定线程池中的最大线程数
        int maximumPoolSize = cpu + 2 +1;

        //设定空闲线程的存活时间
        long keepAliveTime = 2;

        //设置线程池
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit.SECONDS,new PriorityBlockingQueue());

        for(int i=0;i<10;i++){

            tpe.execute(new Runnable() {

                @Override
                void run() {
                    try {
                        System.out.println("cpu是多少 ="+cpu+"========核心线程数为=="+corePoolSize);
                        Thread.sleep(1000);
                        test();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            });


        }

    }
}

如果代码这样写会报错

   Caused by: java.lang.ClassCastException: liuqian.com.liuqianimoocproject.MainActivity$5 cannot be cast to java.lang.Comparable

其中需要把任务Runnable实现Comparable接口才行。

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //获取CPU的数量
        final int cpu = Runtime.getRuntime().availableProcessors();

        //设定线程池中的核心线程数
        final int corePoolSize = cpu +1;

        //设定线程池中的最大线程数
        int maximumPoolSize = cpu + 2 +1;

        //设定空闲线程的存活时间
        long keepAliveTime = 2;

        //设置线程池
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit.SECONDS,new PriorityBlockingQueue());

        for(int i=0;i<10;i++){

            tpe.execute(new MyRunnable() {

                @Override
                void doRun() {
                    try {
                        System.out.println("cpu是多少 ="+cpu+"========核心线程数为=="+corePoolSize);
                        Thread.sleep(1000);
                        test();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            });


        }

    }
abstract  class  MyRunnable implements Runnable ,Comparable<MyRunnable>{
    abstract void doRun();

    @Override
    public void run() {
        doRun();
    }

    @Override
    public int compareTo(@NonNull MyRunnable o) {
        return 0;
    }
}

如此便解决了问题

疑问:
1. 为何此处需要将Runnable实现Comparable接口?
2. android中允许执行的最大任务数是多少个?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值