黑马程序员技术交流社区

标题: JAVA线程-任务 [打印本页]

作者: 血马雄风    时间: 2015-8-23 09:58
标题: JAVA线程-任务
               JAVA线程-任务
一、创建任务
有两种方法:
(1)实现Callable接口,重写call方法。
这里的没有将任务与具体线程进行绑定。而是通过ExecutorService.submit()方法将任务提交给某个线程或是传递给FutureTask。
(2)实现Runnable接口并编写run()方法
         这里的没有将任务与具体线程进行绑定。可以通过将Runnable对象提交给Thread类构造器实现任务与具体线程绑定。      
         public class Task implements Runnable{
             //数据
             ……..
             //方法
             ……..
             //run()
             public void run(){
                ……….
             }
         }

         Thread thrd = new Thread(new Task());
         thrd.start();
   (3)尽管java提供了一些实现了Runable接口的类,并且可在这些类的run()方法体内可描述任务,但是,这违反了任务与线程、任务管理分离地原则,而不提倡使用。
        1)Thread用于创建线程和线程的状态管理等
        2)Future及其子类FutureTask用于任务的管理
        3)TimerTask用于描述计时或周期的任务(这是例外)
二、从任务中产生返回值
1、使用Callable接口
Runnable接口是执行工作的独立任务,它不返回任何值。
可通过实现Callable接口并可以重写Callable接口的call()方法来实现。
Callable接口是一种具有类型参数的范型,其类型参数表示从call()中返回的类型。
并且使用ExecutorService.submit()方法调用实现Callable接口的类的对象。
例如:     
       public Task implements Callable<String> {
           String result;
…….
           public String call(){
               return …+ result;
           }
       }

       //main()
        ExecutorService exec = Executors.new CachedThreadPool();
        String relt = exec.submit(new Task());      // submit()返回一个范型Future对象
        ……..
        exec.shutdown();
    2、使用Future及其子类
三、执行任务
    1、使用Thread类对象创建的线程执行任务
      (1)实现Runnable接口
      (2)调用Thread对象的start()和run()方法
    2、使用执行器(Executor)(即线程池)创建的线程执行任务
      (1)创建一个线程的代价有点高,因为需要与操作系统交互。而将实现Runnable的对象和实现Callable的对象提交给线程池,线程池中的线程会调用run()方法执行任务,当run()返回后,线程也不会死亡,而是在线程池中等待下一个任务。
      (2)使用线程池可以减少并发线程的数量。
      (3)实例
            public Task implements Runnable{ ……..}
        
            //main()
            ExecutorService exec = Executors.new CachedThreadPool();  //创建线程池
            exec.execute(new Task());                              //提交任务
            exec.shutdown();                                     //关闭线程池

四、任务间通信
1、使用管道实现任务间(线程间)输入/输出。
2、JAVA中对应的类为PipedWriter类(允许任务向管道写)和PipedReader类(允许不同任务从同一个管道中读取)。
3、例如:
   /*发送任务*/
   class Sender implements Runnable{
       private Random rand = new Random(47);
       private PipedWriter out = new PipedWriter();    //写入管道
       public PipedWriter get PipedWriter(){return out;}// 获取写入管道对象
      
       public void run(){
           try{
              while(true)
                 for(char c = ‘A’; c <= ‘z’; c++){
                    out.write(c);
                    TimeUnit.MILLISECONDS.sleep(rand.netInt(500));
                 }
           }catch(IOException e){
              print(e + “Sender write exception”);
           }catch(InterruptedException e){
              print(e + “Sender write interrupted”);
           }
       }
   }

/*接收任务*/
   class Receiver implements Runnable{
       private PipedReader in;    //读取管道
       public Receiver(Sender sender) throws IOException{
           //读取管道与指定任务的写入管道绑定
           in = new PipedReader(sender.getPipedWriter());
       }

       public void run(){
           try{
              while(true){
                 printnb(“Read: ” + (char)in.read() + “, ”);
              }
           }catch(IOException e){
              print(e + “Receiver read exception”);
           }
       }
   }

   //main()
   Sender sender = new Sender();              //发送任务
   Receiver receiver = new Receiver(sender);     //接收任务
   ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(sender);
exec.execute(receiver);
TimeUnit.SECONDS.sleep(4);
exec.shutdownNow();

//out
Read: A, Read: B, Read: C, Read: D, Read: F, Read: G, Read: H, Read: I,
java.lang.InterruptedException: sleep interrupted Sender
sleep interrupted
   java.io.InterruptedIOException Receiver read exception

六、取消任务
1、使用使用Future及其子类,这是友好的
2、使终止执行任务的线程,不确定
3、关闭线程池,这也是暴力的,不计后果的
七、线程在哪里
    1、一旦创建了一个程序,就存在一个线程,即main()
    2、隐式创建的线程,即使用执行器(Excutor)创建
    3、显式创建的线程,即直接使用Thread类创建



作者: koibiki    时间: 2015-8-23 10:58
总结得很好




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2