Java并发(三):实例引出并发应用场景
前两篇介绍了一些Java并发的基础知识,博主正巧遇到一种需求:查询数据库,根据查询结果集修改数据库记录,但整个流程是做成了一个schedule的,并且查询比较耗时,并且需要每两分钟执行一次,cpu经常因等待服务器响应的查询结果而进入等待,故需要在此基础上考虑性能优化,sql优化可以提高一些系统效率,同样,多线程也可以...
下面博主做个DEMO引出一些Java并发的实际应用场景:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class TestThread implements Runnable{ private String name; private Integer i = 0; List list = new ArrayList(); public TestThread(String name) { this.name=name; for(int i=0; i<100; i++){ list.add(i); } } @Override public void run() { Long past = System.currentTimeMillis(); get(); System.out.println(System.currentTimeMillis()-past); } private void get(){ while(true){ try{ Thread.sleep(200); }catch(Exception e){ e.printStackTrace(); } synchronized (i){ if(i>=100){ break; } System.out.println(list.get(i++)); } } } public static void main(String[] args) { //线程池方式 ExecutorService exector = new ThreadPoolExecutor(5, 7, 30, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10)); //对于最大线程数和核心线程数的参考值,对于cpu密集型任务,可以选择NCPU+1,对于耗时较长的IO操作,可以选择2*NCPU TestThread a = new TestThread("A"); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); //普通方式 /*TestThread a = new TestThread("A"); new Thread(a).start(); new Thread(a).start(); new Thread(a).start(); new Thread(a).start();*/ } }
TIP:不推荐使用Executors.newFixedThreadPool()来创建线程池,大家看底层代码:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
newFixedThreadPool()方法底层还是调用了new ThreadPoolExecutor(),但线程等待队列(LinkedBlockingQueue)默认是不限定其长度的,意味着有大量线程入队时,会有内存溢出的风险,推荐大家使用new ThreadPoolExecutor()来创建线程池...
通过以上代码(可以跑)感受得到单线程和多线程的性能差距,设备越好,cpu核数越多,应该结果越明显,当然这不是绝对的,有时我们得考虑多线程的上下文切换的时间占用率和多线程同步的性能消耗...另外,我们平常应该使用线程池来管理线程,因为比较方便,JavaAPI也已经将细节实现到位,各位可以用这样线程安全的方式结合索引遍历集合,这样对于集合内的元素就可以多线程遍历并触发各自的操作,例如更新数据库等,可以说非常实用...
多线程使用的主要目的在于:
1、吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。
2、伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能。