如何控制线程并发数
(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中允许执行的最大任务数是多少个?