Java线程(三):JUC包原子性操作类与线程池的简单运用

来源:互联网 发布:手机图片标注软件 编辑:程序博客网 时间:2024/06/04 19:12

JUC(java.util.concurrent)是JAVA 5后新的线程包,可以完全取代原有的java线程处理。主要是三个包:分别为 java.util.concurrent 以及其两个子包:java.util.concurrent.atomic 和 java.util.concurrent.locks 。


一、原子性类操作

1、java.util.concurrent.atomic 在这个包下的都是JUC库的原子性操作类,即线程安全的类。

2、一般只有是类的成员变量的时候,才需要使用,如Servlet是线程不安全的,一般不建议定义成员变量,这时就可以使用 atomic 的线程安全的类。如 AtomicInteger

private volatile int value;

3、java中 int i= 0 ,i++ 不是线程安全,而 AtomicInteger 通过上面的源码实现线程安全。注意看它的访问控制符,是volatile,这个就是保证 AtomicInteger 线程安全的根源:synchronized 关键字和 volatile 修饰符都是保证线程安全的有效方法。


4、Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存重新读取该成员的值,而且,当成员变量值发生变化时,强迫将变化的值重新写入共享内存,这样两个不同的线程在访问同一个共享变量的值时,始终看到的是同一个值。
5、java语言规范指出:为了获取最佳的运行速度,允许线程保留共享变量的副本,当这个线程进入或者离开同步代码块时,才与共享成员变量进行比对,如果有变化再更新共享成员变量。这样当多个线程同时访问一个共享变量时,可能会存在值不同步的现象。而volatile这个值的作用就是告诉VM:对于这个成员变量不能保存它的副本,要直接与共享成员变量交互。
 
6、结论:建议:当多个线程同时访问一个共享变量时,可以使用volatile,而当访问的变量已在synchronized代码块中时,不必使用。缺点:使用volatile将使得VM优化失去作用,导致效率较低,所以要在必要的时候使用。


二、线程池

1、java原有线程实现为,一个Thread类就代表一个线程。举个例子:如生产者和消费者。1个线程负责生产,2个线程负责消费,还需要一个放产品的池子。2个消费线程去池子中消费,如没有产品则等待(wait),等待生产者生产,如有产品了,生产者唤醒消费者(notify()或者notifyAll())消费。2个消费线程需要不停地去获取产品池的现状,有则消费,无则等待。这样的互斥与通信的代码实现起来比较繁琐,使用JUC 包的线程池可以轻松的实现以上的功能。


3、JUC包定义了3中类型的线程池:Executors 类

1)newFixedThreadPool: 固定的线程池。如 Executors.newFixedThreadPool(3)创建线程池,只有3个线程,每次丢很多任务,但是只有三个线程一起处理。

2)newCachedThreadPool:缓存的线程池 有几个任务就可以有几个线程。

3)newSingleThreadExecutor: 一个单一线程,但是当这个线程死后,会再出现一个新的线程:可以实现线程死掉后重新启动。

4)shutdown()-关闭线程;shutdownNow()-立马死掉,即使还有任务


4、实例分析:

/* * newFixedThreadPool()  * 固定的线程池 创建线程池,只有3个,每次丢很多任务,但是只有三个线程一起处理 *  * newCachedThreadPool()  * 缓存的线程池 有几个任务就可以有几个线程 *  * newSingleThreadExecutor() * 一个单一线程,但是当这个线程死后,会再出现一个新的线程:可以实现线程死掉后重新启动 *  */ExecutorService threadPool = Executors.newFixedThreadPool(3);//ExecutorService threadPool = Executors.newCachedThreadPool();//ExecutorService threadPool = Executors.newSingleThreadExecutor();//一个池,6个任务for (int i = 0; i < 6; i++) {final int task = i;threadPool.execute(new Runnable() {@Overridepublic void run() {for (int j = 1; j < 5; j++) {//每个任务单独循环处理5次try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ " is loop off(循环) " + j + " , is for 任务  "+task);}}});}System.out.println("all of 6 tasks(任务) have committed! ");threadPool.shutdown();//关闭线程//threadPool.shutdownNow();//立马死掉,即使还有任务


1)固定线程池的【输出】为:6个任务,但是每次只有3个线程,每个任务干2遍,干完了才会

all of 6 tasks(任务) have committed! pool-1-thread-2 is loop off(循环) 1 , is for 任务  1pool-1-thread-1 is loop off(循环) 1 , is for 任务  0pool-1-thread-3 is loop off(循环) 1 , is for 任务  2pool-1-thread-2 is loop off(循环) 2 , is for 任务  1pool-1-thread-3 is loop off(循环) 2 , is for 任务  2pool-1-thread-1 is loop off(循环) 2 , is for 任务  0pool-1-thread-2 is loop off(循环) 1 , is for 任务  3pool-1-thread-3 is loop off(循环) 1 , is for 任务  4pool-1-thread-1 is loop off(循环) 1 , is for 任务  5pool-1-thread-2 is loop off(循环) 2 , is for 任务  3pool-1-thread-1 is loop off(循环) 2 , is for 任务  5pool-1-thread-3 is loop off(循环) 2 , is for 任务  4


2)缓存池的【输出】结果:6个任务,产生了6线程处理。

all of 6 tasks(任务) have committed! pool-1-thread-2 is loop off(循环) 1 , is for 任务  1pool-1-thread-1 is loop off(循环) 1 , is for 任务  0pool-1-thread-3 is loop off(循环) 1 , is for 任务  2pool-1-thread-4 is loop off(循环) 1 , is for 任务  3pool-1-thread-5 is loop off(循环) 1 , is for 任务  4pool-1-thread-6 is loop off(循环) 1 , is for 任务  5pool-1-thread-1 is loop off(循环) 2 , is for 任务  0pool-1-thread-2 is loop off(循环) 2 , is for 任务  1pool-1-thread-5 is loop off(循环) 2 , is for 任务  4pool-1-thread-3 is loop off(循环) 2 , is for 任务  2pool-1-thread-4 is loop off(循环) 2 , is for 任务  3pool-1-thread-6 is loop off(循环) 2 , is for 任务  5

3)单一线程池的【输出】结果:6个任务,只有一个线程默默的干活。如果这个线程死后,会重新启一个线程。

all of 6 tasks(任务) have committed! pool-1-thread-1 is loop off(循环) 1 , is for 任务  0pool-1-thread-1 is loop off(循环) 2 , is for 任务  0pool-1-thread-1 is loop off(循环) 1 , is for 任务  1pool-1-thread-1 is loop off(循环) 2 , is for 任务  1pool-1-thread-1 is loop off(循环) 1 , is for 任务  2pool-1-thread-1 is loop off(循环) 2 , is for 任务  2pool-1-thread-1 is loop off(循环) 1 , is for 任务  3pool-1-thread-1 is loop off(循环) 2 , is for 任务  3pool-1-thread-1 is loop off(循环) 1 , is for 任务  4pool-1-thread-1 is loop off(循环) 2 , is for 任务  4pool-1-thread-1 is loop off(循环) 1 , is for 任务  5pool-1-thread-1 is loop off(循环) 2 , is for 任务  5

三、使用线程池启动定时器

1、调用 Executors.newScheduledThreadPool()获取 ScheduledExecutorService 定时器调度线程池。

2、一般的定时器,调用 ScheduledExecutorService  的schedule()方法,如 1 秒后输出。

/* * 一般的定时器 */Executors.newScheduledThreadPool(3).schedule(new Runnable(){@Overridepublic void run() {System.out.println("bombing!");}}, 1, TimeUnit.SECONDS);


3、有频率的定时器,调用 ScheduledExecutorService  的 scheduleAtFixedRate() 方法。如 1 秒后输出,每隔 2秒再次输出。

/* * 有频率的定时器 */Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable(){@Overridepublic void run() {System.out.println("bombing!");}}, 1, 2, TimeUnit.SECONDS);



三、Callable和Future 有返回的线程


1、向线程提交任务,任务完成后,可以获取任务的返回结果。

2、Callable返回结果, Future可以拿到结果。Future取得的结果类型和Callable返回类型必须保持一致

3、执行线程池:execute执行,没有返回值;submit有返回结果 。

4、CompletionService 用于提交一组 Callable 任务,其take方法返回已完成的一个 Callable任务对应的Future对象。


package com.newThread;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** *  * CallableAndFuture.java * * @title Callable和Future Callable返回结果, Future可以拿到结果 * @description * @author SAM-SHO  * @Date 2014-8-23 */public class CallableAndFuture {/** * @param args */public static void main(String[] args) {//1-起一个简单的线程池ExecutorService threadPool = Executors.newSingleThreadExecutor();//2-调用//2-1 execute执行,没有返回值//threadPool.execute(command);//2-2 submit有返回结果 Callable返回结果, Future可以拿到结果// Future取得的结果类型和Callable返回的类型必须保持一致Future<String> future = threadPool.submit(new Callable<String>(){@Overridepublic String call() throws Exception {Thread.sleep(2000);return "hello";}});System.out.println("等待结果");try {System.out.println("拿到结果: "+future.get());//拿到结果,拿不到的时候会一直等...//System.out.println("拿到结果: "+future.get(timeout, unit)get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}threadPool.shutdown();//3-固定的线程池,10个线程// CompletionService 用于提交一组 Callable 任务,// 其take方法返回已完成的一个 Callable任务对应的Future对象。ExecutorService threadPool2 = Executors.newFixedThreadPool(10);ExecutorCompletionService<Integer> eCService = new ExecutorCompletionService<Integer>(threadPool2);for (int i = 1; i < 10; i++) {final int seq = i;eCService.submit(new Callable<Integer>() {//一组Callable@Overridepublic Integer call() throws Exception {Thread.sleep(5000);return seq;//返回的值,为int}});}// 谁先完成,就先取谁for (int i = 0; i < 10; i++) {System.out.println("等待...");try {System.out.println(eCService.take().get());//take方法返回对应的Future对象} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}threadPool2.shutdown();}}

0 0