Java5对线程处理的新操作-concurrent包介绍
2015-04-28 18:21
302 查看
上节中简单介绍了传统的jdk中的线程的概念,本节中接着介绍下jdk5之后对线程处理有哪些改变。
首先,介绍下java.util.concurrent包下有个字包atomic(原子的)包,其中的一些类提供原子性操作类,分别是:
atomic包可以对基本数据,数组中的基本数据,对类中的基本数据进行原子性操作。
在介绍了在多线程环境下jdk提供了原子操作类的基本实现后,我们接着介绍线程并发库的应用。
线程池的概念,线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
实例,Tomcat服务器设计思路。
线程池实现:在线程run实现中,while(查询某个线程池中是否有任务==有){执行任务}
jdk中默认提供了,Executes类供开发者使用,该类中提供静态方法用于创建不同类型的线程池。
在线程池学习中大家,只需注意两点,线程池中线程的数量,和我们向线程池中丢了多少任务。
我们不需要自己去把任务交给线程运行,而只需将任务丢到线程池中,由线程池自动帮我们运行,当线程池中没有空闲线程时候我们可以采用多种机制处理线程。处理方式如下:
1. 创建固定数量的连接池。
线程的执行执行结果:
从结果可以看出,我们创建了一个固定三个长度的线程池对象,并且向线程池中丢了10个任务Task,在执行的过程中这些任务会同时被3个线程同时执行,在3个线程执行的过程中,第4个任务并不会执行,而被挂起排队中,因为此时我们创建的是固定数量的线程池,直到3个线程中有一个线程结束时候才会执行第4个任务。
这个就是固定数量的线程池-Fixed线程池,在所有任务都执行完成后,主任务并不死亡,因为线程池中的线程并不死亡,如果要主程序死亡,需要执行shutdown()或者shutdownNow()方法。
2. 创建缓存的线程池
执行结果如下:
程序会自动创建相应数量的线程来处理相应数量的任务,这就是带缓存的线程池。
当线程服务不过来时候时候它自动增加新的线程。线程池中线程数量是不固定的,
当线程服务任务数量变化时候,超时一段时间后我们会将线程收回,不浪费。
3. 创建单个线程的线程池,类似单线程。
执行结果:
根据结果可以看出,在创建单个线程时候,任务是按照放入的顺序单独执行的,即当第一个任务执行完成后会在创建一个线程(还是原来的名字)处理下一个任务,保证存在一个线程,解决线程死亡后重新启动。
4. 定时器线程池,用线程池启动定时器。
对于定时器的线程池操作,
schedule,多久开始执行一次;
scheduleAtFixedRate,多就开始执行一次后,再隔多少秒再执行一次,且不受任务执行时间影响;
scheduleWithFixedDelay,多就开始执行一次后,再隔多少秒再执行一次,且受任务执行时间影响;
补充:
对于线程池对象ExecutorService对象,可以调用submit方法使用实现Callable<V>接口的类,重写该类的V call() throws Exception;方法,此用法可以通过submit返回的Future对象get到call方法的返回值,代码如下:
Future设计模式提高了系统的吞吐量,系统只在需要拿到数据的时候,即调用get的时候才等待线程执行完毕,如果系统不需要得到返回值,我们不需要等待该线程执行完毕.
其中:
Future取得结果类型和Callable返回的结果类型必须一致,泛型技术。
Callable需要调用ExecutorService的submit方法才可以提交。
同时,返回的future对象也可以取消任务,通过cancel方法即可。
cancel方法参数boolean mayInterruptIfRunning区别:
另外, CompletionService用于提交一组Callable任务,其中take方法返回已完成的一个Callable任务对应的Future对象,可以得到返回值。
代码如下:
在代码执行过程中,程序通过ExecutorService类的take()方法删除完成的任务,如果没有取到则等待。
首先,介绍下java.util.concurrent包下有个字包atomic(原子的)包,其中的一些类提供原子性操作类,分别是:
AtomicBoolean, AtomicInteger,AtomicIntegerArray,AtomicIntegerFieldUpdater<T>, AtomicLong,AtomicLongArray,AtomicLongFieldUpdater<T>, AtomicReference<V>,AtomicReferenceArray<E>,AtomicReferenceFieldUpdater<T,V>, AtomicMarkableReference<V>, AtomicStampedReference<V>
atomic包可以对基本数据,数组中的基本数据,对类中的基本数据进行原子性操作。
在介绍了在多线程环境下jdk提供了原子操作类的基本实现后,我们接着介绍线程并发库的应用。
线程池的概念,线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
实例,Tomcat服务器设计思路。
线程池实现:在线程run实现中,while(查询某个线程池中是否有任务==有){执行任务}
jdk中默认提供了,Executes类供开发者使用,该类中提供静态方法用于创建不同类型的线程池。
在线程池学习中大家,只需注意两点,线程池中线程的数量,和我们向线程池中丢了多少任务。
我们不需要自己去把任务交给线程运行,而只需将任务丢到线程池中,由线程池自动帮我们运行,当线程池中没有空闲线程时候我们可以采用多种机制处理线程。处理方式如下:
1. 创建固定数量的连接池。
ExecutorService pool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int task = i; pool.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(20); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName()+": is looping of "+i+" for task is "+task); } } }); }
线程的执行执行结果:
pool-1-thread-3: is looping of 0 for task is 2 pool-1-thread-1: is looping of 0 for task is 0 pool-1-thread-2: is looping of 0 for task is 1 pool-1-thread-2: is looping of 1 for task is 1 pool-1-thread-1: is looping of 1 for task is 0 pool-1-thread-3: is looping of 1 for task is 2 pool-1-thread-2: is looping of 2 for task is 1 pool-1-thread-1: is looping of 2 for task is 0 pool-1-thread-3: is looping of 2 for task is 2 pool-1-thread-2: is looping of 3 for task is 1 pool-1-thread-3: is looping of 3 for task is 2 pool-1-thread-1: is looping of 3 for task is 0
从结果可以看出,我们创建了一个固定三个长度的线程池对象,并且向线程池中丢了10个任务Task,在执行的过程中这些任务会同时被3个线程同时执行,在3个线程执行的过程中,第4个任务并不会执行,而被挂起排队中,因为此时我们创建的是固定数量的线程池,直到3个线程中有一个线程结束时候才会执行第4个任务。
这个就是固定数量的线程池-Fixed线程池,在所有任务都执行完成后,主任务并不死亡,因为线程池中的线程并不死亡,如果要主程序死亡,需要执行shutdown()或者shutdownNow()方法。
2. 创建缓存的线程池
ExecutorService pool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int task = i; pool.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(20); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName()+": is looping of "+i+" for task is "+task); } } }); }
执行结果如下:
pool-1-thread-1: is looping of 0 for task is 0 pool-1-thread-3: is looping of 0 for task is 2 pool-1-thread-5: is looping of 0 for task is 4 pool-1-thread-7: is looping of 0 for task is 6 pool-1-thread-2: is looping of 0 for task is 1 pool-1-thread-4: is looping of 0 for task is 3 pool-1-thread-6: is looping of 0 for task is 5 pool-1-thread-8: is looping of 0 for task is 7 pool-1-thread-10: is looping of 0 for task is 9 pool-1-thread-9: is looping of 0 for task is 8 pool-1-thread-1: is looping of 1 for task is 0
程序会自动创建相应数量的线程来处理相应数量的任务,这就是带缓存的线程池。
当线程服务不过来时候时候它自动增加新的线程。线程池中线程数量是不固定的,
当线程服务任务数量变化时候,超时一段时间后我们会将线程收回,不浪费。
3. 创建单个线程的线程池,类似单线程。
ExecutorService pool = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int task = i; pool.execute(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(500); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName()+ ": is looping of " + i + " for task is "+ task); } } }); }
执行结果:
pool-1-thread-1: is looping of 0 for task is 0 pool-1-thread-1: is looping of 1 for task is 0 pool-1-thread-1: is looping of 2 for task is 0 pool-1-thread-1: is looping of 3 for task is 0 pool-1-thread-1: is looping of 4 for task is 0 pool-1-thread-1: is looping of 5 for task is 0 pool-1-thread-1: is looping of 6 for task is 0 pool-1-thread-1: is looping of 7 for task is 0 pool-1-thread-1: is looping of 8 for task is 0 pool-1-thread-1: is looping of 9 for task is 0 pool-1-thread-1: is looping of 0 for task is 1 pool-1-thread-1: is looping of 1 for task is 1 pool-1-thread-1: is looping of 2 for task is 1 pool-1-thread-1: is looping of 3 for task is 1 pool-1-thread-1: is looping of 4 for task is 1
根据结果可以看出,在创建单个线程时候,任务是按照放入的顺序单独执行的,即当第一个任务执行完成后会在创建一个线程(还是原来的名字)处理下一个任务,保证存在一个线程,解决线程死亡后重新启动。
4. 定时器线程池,用线程池启动定时器。
ScheduledExecutorService executorService=Executors.newScheduledThreadPool(3); executorService.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("execute1"); } }, 2 ,1 , TimeUnit.SECONDS); executorService.schedule(new Runnable() { public void run() { System.out.println("execute2"); } }, 2 ,TimeUnit.SECONDS);
对于定时器的线程池操作,
schedule,多久开始执行一次;
scheduleAtFixedRate,多就开始执行一次后,再隔多少秒再执行一次,且不受任务执行时间影响;
scheduleWithFixedDelay,多就开始执行一次后,再隔多少秒再执行一次,且受任务执行时间影响;
补充:
对于线程池对象ExecutorService对象,可以调用submit方法使用实现Callable<V>接口的类,重写该类的V call() throws Exception;方法,此用法可以通过submit返回的Future对象get到call方法的返回值,代码如下:
ExecutorService se = Executors.newSingleThreadExecutor(); Future<String> future = se.submit(new Callable<String>() { public String call() throws Exception { Thread.sleep(3000); return "abc"; } }); System.out.println("等待... ..."); System.out.println("拿到结果:"+future.get());//1,TimeUnit.SECONDS System.out.println(future.get());
Future设计模式提高了系统的吞吐量,系统只在需要拿到数据的时候,即调用get的时候才等待线程执行完毕,如果系统不需要得到返回值,我们不需要等待该线程执行完毕.
其中:
Future取得结果类型和Callable返回的结果类型必须一致,泛型技术。
Callable需要调用ExecutorService的submit方法才可以提交。
同时,返回的future对象也可以取消任务,通过cancel方法即可。
cancel方法参数boolean mayInterruptIfRunning区别:
ExecutorService se = Executors.newSingleThreadExecutor(); Future<String> future = se.submit(new Callable<String>() { public String call() throws Exception { for (int i = 0; i < 100; i++) { System.out.println(i); Thread.sleep(100); } return "abc"; } }); Thread.sleep(10); future.cancel(true);// false,当为true时cancel一但执行线程即将结束;为false时,会等到线程执行完毕 System.out.println("等待... ..."); System.out.println("拿到结果:"+future.get());//1,TimeUnit.SECONDS System.out.println(future.get());
另外, CompletionService用于提交一组Callable任务,其中take方法返回已完成的一个Callable任务对应的Future对象,可以得到返回值。
代码如下:
ExecutorService pool = Executors.newFixedThreadPool(10); CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(pool); for (int i = 0; i < 10; i++) { final int task = i; completionService.submit(new Callable<Integer>() { public Integer call() throws Exception { Thread.sleep(new Random().nextInt(500) * task); return task; } }); } for (int i = 0; i < 12; i++) { System.out.println(completionService.take().get()); System.out.println("==="+i); }
在代码执行过程中,程序通过ExecutorService类的take()方法删除完成的任务,如果没有取到则等待。
相关文章推荐
- java 常见的文件字符处理操作 进程与线程
- JAVA 中无锁的线程安全整数 AtomicInteger介绍和使用
- 线程并发线程安全介绍及java.util.concurrent包下类介绍
- Java 线程的基本状态和操作
- 线程高级应用-心得4-java5线程并发库介绍,及新技术案例分析
- Java线程 锁对象Lock-同步问题比sychronized更完美的处理方式
- Java多线程(2)——线程状态,操作,优先级
- java基于移位操作实现二进制处理的方法示例
- Java I/O 操作及优化详细介绍
- java的服务是每收到一个请求就新开一个线程来处理吗?tomcat呢?
- Java 处理 XML 的三种主流技术及介绍
- JAVAWEB开发之JDBC详解(连接操作数据库、处理大数据、批处理)
- java 操作windows 共享目录方法介绍
- 线程基础:线程(2)——JAVA中的基本线程操作(上)
- 线程基础:线程(3)——JAVA中的基本线程操作(中)
- 线程基础:线程(4)——JAVA中的基本线程操作(下)
- Java中的string介绍和字符串常见操作
- Java 处理 XML 的三种主流技术及介绍
- 在Java中使用Jedis操作Redis,在高并发的情况下,应用卡死、报无法获取连接错误的处理方式
- Java数据库的操作——DBUtils工具类结果集处理的方式有几种?