java7 concurrency cookbook(第四章)

线程执行器(Thread Executors)

1、创建线程执行器

2、创建定长线程执行器

3、在返回结果的线程执行器中执行任务

4、运行多任务并且处理第一个返回结果

5、运行多任务并且处理所有返回结果

6、在一定延时后执行器运行任务

7、执行器中周期性的运行一个任务

8、取消线程执行器中的一个任务

9、控制执行器中已经完成的任务

10、分离执行器中的任务的开启,并分别处理结果。

11、控制被执行器拒绝的任务。


这本书的最大特点就是通过代码感知知识点。开启本章的内容。

通常情况下,我们可以通过运行多个thread线程开启多线程环境下的编程任务。但是在需要开启成百上千任务的环境下,这种多线程编程模式显然会成为瓶颈。

从java5开始,jdk就提供了并发编程框架(Eexcutor framwork) ,executor框架中,只需把任务分配给executor,executor负责初始化、运行线程。另一个好处是executor框架里面提供了callable接口。Callable接口有以下两个好处。

1、接口的主方法调用call()可以获得返回结果。

2、采用callable接口传递任务给executor,我们能够获得一个实现了Future接口的的对象。我们能够通过使用这个对象控制状态和返回结果。

一、创建线程执行器

package jav7concurrencycookbook.fouthpassage;


import java.util.Date;

import java.util.concurrent.TimeUnit;


public class Task implements Runnable {


 private Date initDate;

 private String name;

 public Task(String name){

  this.name=name;

  initDate=new Date();

 }

 @Override

 public void run() {

  // TODO Auto-generated method stub

     System.out.printf("%s: Task $s created on %s",Thread.currentThread().getName(),name,this.initDate);

     try{

      Long duration=(long)(Math.random()*10);

      System.out.printf("%s: Task %s: Doing a task during %d seconds\n",Thread.currentThread().getName(),name,duration);

      TimeUnit.SECONDS.sleep(duration);

     }catch(InterruptedException e){

      e.printStackTrace();

     }

     System.out.printf("%s: Task %s: Finished on: %s\n",Thread.

       currentThread().getName(),name,new Date());

 }


}


package jav7concurrencycookbook.fouthpassage;


import java.util.concurrent.Executors;

import java.util.concurrent.ThreadPoolExecutor;


public class Server {

 private ThreadPoolExecutor executor;

 public Server(){

  //Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available, and uses the provided ThreadFactory to create new threads when needed

  executor=(ThreadPoolExecutor)Executors.newCachedThreadPool();

     

 }

 public void executeTask(Task task){

  System.out.printf("Server: A new task has arrived\n");

  executor.execute(task);//execute task

  System.out.printf("Server: Pool Size: %d\n",executor.

    getPoolSize());

    System.out.printf("Server: Active Count: %d\n",executor.

    getActiveCount());

    System.out.printf("Server: Completed Tasks: %d\n",executor.

    getCompletedTaskCount());

 }

 public void endServer() {

  executor.shutdown();

  }

 /**

  * @param args

  */

 public static void main(String[] args) {

  // TODO Auto-generated method stub

  Server server=new Server();

  for (int i=0; i<5; i++){

  Task task=new Task("Task "+i);

  server.executeTask(task);

  }

  server.endServer();//注意任务执行完毕关闭线程池(ThreadPoolExecutor)

 }


}


二、创建定长线程执行器

executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(5);//线程池的大小为5

newSingleThreadExecutor()//线程池的大小为1,每次只能执行一个任务

三、在返回结果的线程执行器中执行任务

Executor framwork的好处之一就是你能够同时运行任务并获得结果。Java 并发API提供了以下两个接口:

1 Callable:该接口有一个call()方法。call()方法可以实现任务逻辑。同时,Callable接口是一个有个参数接口,有我们指定返回的值类型。

2、Future:该接口有一些方法,获取Callable对象的返回结果,并且管理Callable的状态。



This interface has some methods to obtain the result generated by a

Callable object and to manage its state.


package jav7concurrencycookbook.fouthpassage;


import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.TimeoutException;

//实现Callable接口指定返回类型为Integer

public class FactorialCalculator implements Callable<Integer> {

 private Integer number;


 

 public FactorialCalculator(Integer number){


  this.number=number;

     }

     @Override

     public Integer call() throws Exception {

     int result = 1;

     if ((number==0)||(number==1)) {

    result=1;

  } else {

  for (int i=2; i<=number; i++) {

  result*=i;

  TimeUnit.MILLISECONDS.sleep(20);

  }

  }

      System.out.printf("%s: %d\n",Thread.currentThread().

   getName(),result);

      return result;

     }


        public static void main(String[] args) {

        ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(10);

         List<Future<Integer>> resultList=new ArrayList<Future<Integer>>();

          Random random=new Random();

         for (int i=0; i<10; i++){

      Integer number= random.nextInt(10);

      FactorialCalculator calculator=new FactorialCalculator(number);

      Future<Integer> result=executor.submit(calculator);

      try {

    result.get(500, TimeUnit.SECONDS);//等待500秒,如果获取不到数据抛异常。

   } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

   } catch (ExecutionException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

   } catch (TimeoutException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

   }//等待500秒

      resultList.add(result);

 }

 do {

  System.out.printf("Main: Number of Completed Tasks:%d\n",executor.getCompletedTaskCount());

  for (int i=0; i<resultList.size(); i++) {

   Future<Integer> result=resultList.get(i);

   

   System.out.printf("Main: Task %d: %s\n",i,result.

   isDone());

   }

  try {

   TimeUnit.MILLISECONDS.sleep(50);

   } catch (InterruptedException e) {

   e.printStackTrace();

   }

 }while (executor.getCompletedTaskCount()<resultList.size());

 System.out.printf("Main: Results\n");

 for (int i=0; i<resultList.size(); i++) {

  Future<Integer> result=resultList.get(i);

 

  Integer number=null;

  try {

  number=result.get();

  } catch (InterruptedException e) {

  e.printStackTrace();

  } catch (ExecutionException e) {

  e.printStackTrace();

  }

 

  System.out.printf("Main: Task %d: %d\n",i,number);

 }

 executor.shutdown();

}


}

四、运行多任务并且处理第一个返回结果

使用场景,如果有多个排序算法,你指关心哪个是最快的,那么可以使用该方法。

下面的例子是用户被两种机制验证,如果有一个机制验证通过认为该用户有效。

package jav7concurrencycookbook.fouthpassage;


import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class TaskValidator implements Callable<String> {

 private UserValidator validator;

 private String user;

 private String password;


 public TaskValidator(UserValidator validator, String user, String password) {

  this.validator = validator;

  this.user = user;

  this.password = password;

 }


 @Override

 public String call() throws Exception {

  // TODO Auto-generated method stub

  if (!validator.validate(user, password)) {

   System.out.printf("%s: The user has not been found\n",

     validator.getName());

   throw new Exception("Error validating user");

  }

  System.out.printf("%s: The user has been found\n", validator.getName());

  return validator.getName();

 }


 public static void main(String[] args) {

  String username = "test";

  String password = "test";

  UserValidator ldapValidator = new UserValidator("LDAP");//认证1

  UserValidator dbValidator = new UserValidator("DataBase");//认证2

  TaskValidator ldapTask = new TaskValidator(ldapValidator, username,password);//认证1任务

  TaskValidator dbTask = new TaskValidator(dbValidator, username,

    password);//认证2任务

  List<TaskValidator> taskList = new ArrayList<TaskValidator>();//绑定为一个任务链

  taskList.add(ldapTask);

  taskList.add(dbTask);

  ExecutorService executor = (ExecutorService) Executors

    .newCachedThreadPool();

  String result;

  try {

   result = executor.invokeAny(taskList);//只要有一个通过就可以

   System.out.printf("Main: Result: %s\n", result);

  } catch (InterruptedException e) {

   e.printStackTrace();

  } catch (ExecutionException e) {

   e.printStackTrace();

  }

  executor.shutdown();

  System.out.printf("Main: End of the Execution\n");


 }


}

返回的结果有四种情况:

1、两者都为true

2、第一个为true 第二个抛异常

3、第一个抛异常 第二个为true

4、两个都抛异常

五、运行多任务并且处理所有返回结果

List<Future<Result>>resultList=null;//返回的结果放置到Future<Result>链表中。

List<Task> taskList=new ArrayList<>();

for (int i=0; i<3; i++){

Task task=new Task(i);

taskList.add(task);

}

resultList=executor.invokeAll(taskList);

try {

resultList=executor.invokeAll(taskList);

} catch (InterruptedException e) {

e.printStackTrace();

}


executor.shutdown();

System.out.println("Main: Printing the results");

for (int i=0; i<resultList.size(); i++){

Future<Result> future=resultList.get(i);

try {

Result result=future.get();

System.out.println(result.getName()+": "+result.

getValue());

} catch (InterruptedException | ExecutionException e) {

e.printStackTrace();

}

}


为防止长时间不返回,invokeAll(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit): 如果在规定时间内不返回,就跑错。


六、在一定延时后执行器运行任务

ScheduledThreadPoolExecutor executor=(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);

for (int i=0; i<5; i++) {

Task task=new Task("Task "+i);

executor.schedule(task,i+1 , TimeUnit.SECONDS);

}

public ScheduledFuture<?> schedule(Runnable command,
                          long delay,                          TimeUnit unit)

Description copied from interface: ScheduledExecutorService

Creates and executes a one-shot action that becomes enabled after the given delay.



七、执行器中周期性的运行一个任务


ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                     long initialDelay,
                                     long period,                                     TimeUnit unit)

Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor. If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

创建和执行一个周期性的行为,使得在initalDelay时间后开始,在initialDelay+period时间后再来,initialDelay + 2 * period时间内再来。如果一个正在执行的任务报错,那么接下来的任务都会被一致。或者,任务通过被取消或者停止的形式被执行。如果任务的任何执行时间比周期时间长,那么接下来的执行将要延迟,不会并发执行。

八、取消线程执行器中的一个任务

Future<String> result=executor.submit(task);

result.cancel(true);

九、控制执行器中已经完成的任务

FutureTask类提供了一个叫做done()的方法,允许你在执行器中执行的任务完成之后继续一些执行一些代码。这个功能可以使用在线程有后续操作的场景,比如产生一个报告或者发送一个email或者释放资源。这个方法是FutureTask的内置方法,该方法无论在任务被取消或者正常完成之后都会执行。缺省情况下,这个方法是空的,我们可以通过实现FutureTask类实现该方法。


@Override

protected void done() {

if (isCancelled()) {

System.out.printf("%s: Has been canceled\n",name);

} else {

System.out.printf("%s: Has finished\n",name);

}

}


public ResultTask(Callable<String> callable) {

super(callable);

this.name=((ExecutableTask)callable).getName();

}

首先创建实现callnable接口的类,然后创建实现FutureTask<String>接口的类。将第一个类放置到第二个类中。并在第二个类覆盖done方法去实现done逻辑(写日志,发送email等)。

十、分离执行器中的任务的开启,并分别处理结果。

Future<V> poll(long timeout,             TimeUnit unit)
               throws InterruptedException

CompletionService

实现了生产者和消费者的异步解耦。生产者提交任务,消费者按照任务完成的顺序获取任务并处理结果。CompletionService 可以实现异步I/O.

poll(): The version of the poll() method without arguments checks if there are any Future objects in the queue. If the queue is empty, it returns null immediately.

Otherwise, it returns its first element and removes it from the queue. off take(): This method, without arguments, checks if there are any Future objects in

the queue. If it is empty, it blocks the thread until the queue has an element. When the queue has elements, it returns and deletes its first element from the queue.


Retrieves and removes the Future representing the next completed task, waiting if necessary up to the specified wait time if none are yet present.




package jav7concurrencycookbook.fouthpassage;

import java.util.concurrent.CompletionService;

public class ReportRequest implements Runnable {

 private String name;

 private CompletionService<String> service;

 public ReportRequest(String name, CompletionService<String>service){

 this.name=name;

 this.service=service;

 }

 @Override

 public void run() {

  // TODO Auto-generated method stub

  ReportGenerator reportGenerator=new ReportGenerator(name,"Report");

service.submit(reportGenerator);//放置资源

 }

}




package jav7concurrencycookbook.fouthpassage;

import java.util.concurrent.CompletionService;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.Future;

import java.util.concurrent.TimeUnit;

public class ReportProcessor implements Runnable {

 private CompletionService<String> service;

 private boolean end;

 public ReportProcessor(CompletionService<String> service) {

  this.service = service;

  end = false;

 }

 @Override

 public void run() {

  // TODO Auto-generated method stub

  while (!end) {

   Future<String> result = null;//结果

   try {

    result = service.poll(20, TimeUnit.SECONDS);//从队列里面获取数据

   } catch (InterruptedException e1) {

    // TODO Auto-generated catch block

    e1.printStackTrace();

   }

   if (result != null) {//如果获取到了

    String report;

    try {

     report = result.get();

     System.out.printf("ReportReceiver:%s\n",

       report);

    } catch (ExecutionException e) {

     e.printStackTrace();

    } catch (InterruptedException e) {

     // TODO Auto-generated catch block

     e.printStackTrace();

    }

   }

   System.out.printf("ReportSender: End\n");

  }

 }

 public void setEnd(boolean end) {

  this.end = end;

 }

}



package jav7concurrencycookbook.fouthpassage;

import java.util.concurrent.CompletionService;

import java.util.concurrent.ExecutorCompletionService;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

public class Main {

 /**

  *

  */

 public static void main(String[] args) {

  // TODO Auto-generated method stub

  ExecutorService executor=(ExecutorService)Executors.

    newCachedThreadPool();

  CompletionService<String> service=new ExecutorCompletionService<String>(executor);

  ReportRequest faceRequest=new ReportRequest("Face", service);//放置到队列里面

  ReportRequest onlineRequest=new ReportRequest("Online", service);//放置到队列里面

  Thread faceThread=new Thread(faceRequest);

  Thread onlineThread=new Thread(onlineRequest);

  ReportProcessor processor=new ReportProcessor(service);//获取

  Thread senderThread=new Thread(processor);

  System.out.printf("Main: Starting the Threads\n");

  faceThread.start();

  onlineThread.start();

  senderThread.start();

  try {

   System.out.printf("Main: Waiting for the report generators.\n");

   faceThread.join();

   onlineThread.join();

   } catch (InterruptedException e) {

   e.printStackTrace();

   }

  System.out.printf("Main: Shutting down the executor.\n");

  executor.shutdown();

  try {

  executor.awaitTermination(1, TimeUnit.DAYS);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  processor.setEnd(true);

  System.out.println("Main: Ends");

 }

十一、控制被执行器拒绝的任务。

public class RejectedTaskController implements  RejectedExecutionHandler

ThreadPoolExecutor executor=(ThreadPoolExecutor) Executors.newCachedThreadPool();

executor.setRejectedExecutionHandler(controller);

被拒绝的任务可以通过另外配置RejectedExecutionHandler实用自己的拒绝机制处理。



转载于:https://my.oschina.net/zjItLife/blog/354620

When you work with a computer, you can do several things at once. You can hear music while you edit a document in a word processor and read your e-mail. This can be done because your operating system allows the concurrency of tasks. Concurrent programming is about the elements and mechanisms a platform offers to have multiple tasks or programs running at once and communicate with each other to exchange data or to synchronize with each other. Java is a concurrent platform and offers a lot of classes to execute concurrent tasks inside a Java program. With each version, Java increases the functionalities offered to programmers to facilitate the development of concurrent programs. This book covers the most important and useful mechanisms included in Version 7 of the Java concurrency API, so you will be able to use them directly in your applications, which are as follows: f f t e n . d u o l Basic thread management w.codec w w Thread synchronization mechanisms f f Thread creation and management delegation with executors f f Fork/Join framework to enhance the performance of your application f f Data structures for concurrent programs f f Adapting the default behavior of some concurrency classes to your needs f f Testing Java concurrency applications f f What this book covers Chapter 1, Thread Management will teach the readers how to make basic operations with threads. Creation, execution, and status management of the threads are explained through basic examples. Chapter 2, Basic Thread Synchronization will teach the readers to use the low-level Java mechanisms to synchronize a code. Locks and the synchronized keyword are explained in detail. Chapter 3, Thread Synchronization Utilities will teach the readers to use the high-level utilities of Java to manage the synchronization between the threads in Java. It includes an explanation of how to use the new Java 7 Phaser class to synchronize tasks divided into phases. Chapter 4, Thread Executors will teach the readers to delegate the thread management to executors. They allow running, managing, and getting the results of concurrent tasks. Chapter 5, Fork/Join Framework will teach the readers to use the new Java 7 Fork/Join framework. It’s a special kind of executor oriented to execute tasks that will be divided into smaller ones using the divide and conquer technique. Chapter 6, Concurrent Collections will teach the readers to how to use some concurrent data structures provided by the Java language. These data structures must be used in concurrent programs to avoid the use of synchronized blocks of code in their implementation. Chapter 7, Customizing Concurrency Classes will teach the readers how to adapt some of the most useful classes of the Java concurrency API to their needs. Chapter 8, Testing Concurrent Applications will teach the readers how to obtain information about the status of some of the most useful structures of the Java 7 concurrency API. The readers will also learn how to use some free tools to debug concurrent applications, such as the Eclipse, NetBeans IDE, or FindBugs applications to detect possible bugs on their applications.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值