在探讨多线程之前,我们先来看看下面几个问题
首先认识下多线程是个什么?
在我理解,多线程就是多个指令流,并发执行,线程之间没有相互依赖关系,没有先后顺序。
多线程的作用是用来干什么的?
多线程应用程序将程序划分为多个独立的任务,多线程主要是对程序的响应速度,运行的效率会有质的飞越。
多线程一定能够提高效率吗?
上面提到过,多线能够提高程序的响应速度和效率,其实不是所有场景多线程都能提高程序的响应速度和效率的,假设有两个场景:
1,现在一张桌子上有两个苹果,一个人去拿,和两个人去哪,两种情况,那种情况先拿到苹果,两个人去拿苹果一定快吗?答案是不一定。
2,现在有一个注满水的水塘,现在需要把池塘的水抽干,现在问题来了,用一个抽水机快 还是用10个抽水机速度快,答案显而易见,当然是10个抽水机快。
多线程是一个复杂的东西,多线程并不一定能提供程序的运行的效率,多线程有自己的应用场景,当我们的程序需要处理一个繁杂的任务的时候,耗时很长,而这个任务,并不具备原子性,
能够将任务拆分成多个线程来执行。
但是运用多线程技术的时候,需要考虑到的问题,多线程会占用cpu和内存资源,如果线程多了,cpu负担太大,多线程在访问公共资源的时候,很有可能会出现后一个线程覆盖前一个
线程的公共资源的内容。
现在和大家分享一种多线程的应用场景和具体实现。
我本人是从事互联网电商行业,现在分享一下我工作中对多线程的应用,在电商行业中,会存在这样一种用户场景,现在有2000个商品信息用excel保存,需要把这2000个商品入库,在入库
的途中,还会生成促销价等一些列的操作,如果用单线程的话,处理的速度会非常的缓慢。这个时候多线程就体现出它的优势了。
在这之前,我们先来看一个东西,现在有一个 ArrayList<Product> 这个ArrayList里面 放了2000个Product对象,假设现在我需要用多线程让这2000个商品入库,这么处理?
首先我们知道,List 对象里面是可以存放任意类型的对象,我们可以把装有2000个Product对象的ArrayList 拆分成20个list,每个一个list中则存放100个商品。数据格式大概
这样子的List<List<...>,List<....>,List<....>>,一个大的List集合中存放若干个小的List 集合,每一个线程来处理一个小的list。
再来认识几个东西:
Executors:创建线程和管理线程的类,Executors.newFixedThreadPool(ing arg) 此方法是用来创建一个线程池,参数表示创建线程池中线程的个数。
method:execute(),用来执行任务
CountDownLatch:线程的辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
method: countDown(),当前线程调用此方法,则计数减一
awaint(),调用此方法会一直阻塞当前线程,直到计时器的值为0
了解了以上之后,直接上代码:
public List<E> startTreadsProudce(List<T> activityIdList, Integer eachPageSize){
//此方法把activityIdList 调用subList方法(方法如下),切割成如果个小的list 放入totalList中
List<List<T>> totalList = (List<List<T>>)subList(activityIdList, eachPageSize, totalPageCount);
//用来接收每个线程处理返回的返回值
final List<E> resultList = new CopyOnWriteArrayList<E>();
//辅助类,用来计数和线程没执行完处于等待状态
final CountDownLatch countDownLatch = new CountDownLatch(totalList.size());
//创建线程池,线程池的个数为 切割后的list总数
final ExecutorService executorService = Executors.newFixedThreadPool(totalList.size());
//多线程开始
for (final List<T> list : totalList) {
Runnable run = new Runnable() {
public void run() {
try {
//处理入库操作
List<E> itemList = produce(list);
resultList.addAll(itemList);
} catch (Exception ex) {
logger.error("BaseCurrentThreadsManager.startCurrentTreadsProudce() error: ", ex);
} finally {
//当线程执行完,计数减一
countDownLatch.countDown();
}
}
};
//线程执行
executorService.submit(run);
}
try {
//如果线程没有执行完,则一直处于等待状态
countDownLatch.await();
} catch (InterruptedException e) {
logger.error("BaseCurrentThreadsManager.startCurrentTreadsProudce() --> countDownLatch.await() error: " , e);
}finally{
//执行完后关闭线程
executorService.shutdown();
}
return resultList;
}
public static <T> List<List<T>> subList(List<T> list, Integer eachPageSize, Integer totalPageCount){
List<List<T>> returnBatchList = new ArrayList<List<T>>();
if(CollectionUtils.isNotEmpty(list)){
int nextPageCount = 0;
int prePageCount = 0;
int totalPageNum = (list.size() + eachPageSize - 1)/ eachPageSize;
//actually pageNumber is totalPageNum
for (int pageCount = 1 ; pageCount <= totalPageNum ; pageCount++) {
prePageCount = (pageCount - 1) * eachPageSize;
if(pageCount == totalPageNum){
nextPageCount = list.size();
}else{
nextPageCount = pageCount * eachPageSize;
}
returnBatchList.add(list.subList(prePageCount , nextPageCount));
}
}
return returnBatchList;
}
以上均是自己总结,如有错误,请欢迎批评指正。谢谢!
首先认识下多线程是个什么?
在我理解,多线程就是多个指令流,并发执行,线程之间没有相互依赖关系,没有先后顺序。
多线程的作用是用来干什么的?
多线程应用程序将程序划分为多个独立的任务,多线程主要是对程序的响应速度,运行的效率会有质的飞越。
多线程一定能够提高效率吗?
上面提到过,多线能够提高程序的响应速度和效率,其实不是所有场景多线程都能提高程序的响应速度和效率的,假设有两个场景:
1,现在一张桌子上有两个苹果,一个人去拿,和两个人去哪,两种情况,那种情况先拿到苹果,两个人去拿苹果一定快吗?答案是不一定。
2,现在有一个注满水的水塘,现在需要把池塘的水抽干,现在问题来了,用一个抽水机快 还是用10个抽水机速度快,答案显而易见,当然是10个抽水机快。
多线程是一个复杂的东西,多线程并不一定能提供程序的运行的效率,多线程有自己的应用场景,当我们的程序需要处理一个繁杂的任务的时候,耗时很长,而这个任务,并不具备原子性,
能够将任务拆分成多个线程来执行。
但是运用多线程技术的时候,需要考虑到的问题,多线程会占用cpu和内存资源,如果线程多了,cpu负担太大,多线程在访问公共资源的时候,很有可能会出现后一个线程覆盖前一个
线程的公共资源的内容。
现在和大家分享一种多线程的应用场景和具体实现。
我本人是从事互联网电商行业,现在分享一下我工作中对多线程的应用,在电商行业中,会存在这样一种用户场景,现在有2000个商品信息用excel保存,需要把这2000个商品入库,在入库
的途中,还会生成促销价等一些列的操作,如果用单线程的话,处理的速度会非常的缓慢。这个时候多线程就体现出它的优势了。
在这之前,我们先来看一个东西,现在有一个 ArrayList<Product> 这个ArrayList里面 放了2000个Product对象,假设现在我需要用多线程让这2000个商品入库,这么处理?
首先我们知道,List 对象里面是可以存放任意类型的对象,我们可以把装有2000个Product对象的ArrayList 拆分成20个list,每个一个list中则存放100个商品。数据格式大概
这样子的List<List<...>,List<....>,List<....>>,一个大的List集合中存放若干个小的List 集合,每一个线程来处理一个小的list。
再来认识几个东西:
Executors:创建线程和管理线程的类,Executors.newFixedThreadPool(ing arg) 此方法是用来创建一个线程池,参数表示创建线程池中线程的个数。
method:execute(),用来执行任务
CountDownLatch:线程的辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
method: countDown(),当前线程调用此方法,则计数减一
awaint(),调用此方法会一直阻塞当前线程,直到计时器的值为0
了解了以上之后,直接上代码:
public List<E> startTreadsProudce(List<T> activityIdList, Integer eachPageSize){
//此方法把activityIdList 调用subList方法(方法如下),切割成如果个小的list 放入totalList中
List<List<T>> totalList = (List<List<T>>)subList(activityIdList, eachPageSize, totalPageCount);
//用来接收每个线程处理返回的返回值
final List<E> resultList = new CopyOnWriteArrayList<E>();
//辅助类,用来计数和线程没执行完处于等待状态
final CountDownLatch countDownLatch = new CountDownLatch(totalList.size());
//创建线程池,线程池的个数为 切割后的list总数
final ExecutorService executorService = Executors.newFixedThreadPool(totalList.size());
//多线程开始
for (final List<T> list : totalList) {
Runnable run = new Runnable() {
public void run() {
try {
//处理入库操作
List<E> itemList = produce(list);
resultList.addAll(itemList);
} catch (Exception ex) {
logger.error("BaseCurrentThreadsManager.startCurrentTreadsProudce() error: ", ex);
} finally {
//当线程执行完,计数减一
countDownLatch.countDown();
}
}
};
//线程执行
executorService.submit(run);
}
try {
//如果线程没有执行完,则一直处于等待状态
countDownLatch.await();
} catch (InterruptedException e) {
logger.error("BaseCurrentThreadsManager.startCurrentTreadsProudce() --> countDownLatch.await() error: " , e);
}finally{
//执行完后关闭线程
executorService.shutdown();
}
return resultList;
}
public static <T> List<List<T>> subList(List<T> list, Integer eachPageSize, Integer totalPageCount){
List<List<T>> returnBatchList = new ArrayList<List<T>>();
if(CollectionUtils.isNotEmpty(list)){
int nextPageCount = 0;
int prePageCount = 0;
int totalPageNum = (list.size() + eachPageSize - 1)/ eachPageSize;
//actually pageNumber is totalPageNum
for (int pageCount = 1 ; pageCount <= totalPageNum ; pageCount++) {
prePageCount = (pageCount - 1) * eachPageSize;
if(pageCount == totalPageNum){
nextPageCount = list.size();
}else{
nextPageCount = pageCount * eachPageSize;
}
returnBatchList.add(list.subList(prePageCount , nextPageCount));
}
}
return returnBatchList;
}
以上均是自己总结,如有错误,请欢迎批评指正。谢谢!