java多线程相关

Wesley13
• 阅读 602

Runnable

runnable是线程实现的一种方式(接口实现),它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable的实现运行多线程程序,Thread类在调用start()函数后就是执行的是runnable的run()函数。runnable的声明如下:

public interface Runnable { 

/**

     * When an object implementing interface Runnable is used

     * to create a thread, starting the thread causes the object's

     * run method to be called in that separately executing thread.

     * @see     java.lang.Thread#run()

     */

public abstract void run(); 

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

通过实现Runnable接口来创建Thread线程:

步骤1:创建实现Runnable接口的类:

class SomeRunnable implements Runnable
{
    public void run()
    {
      //do something here
    }
}

步骤2:创建一个类对象:

       Runnable oneRunnable = new SomeRunnable();

步骤3:由Runnable创建一个Thread对象:

       Thread oneThread = new Thread(oneRunnable);

步骤4:启动线程:

        oneThread.start();

至此,一个线程就创建完成了。

注释:线程的执行流程很简单,当执行代码oneThread.start();时,就会执行oneRunnable对象中的void run();方法,

该方法执行完成后,线程就消亡了。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Callable

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 :

public interface Callable

/**

  * Computes a result, or throws an exception if unable to do so.

   *

  * @return  computed result

* @throws  Exception if unable to compute a result

*/

V call() throws Exception; 

通过实现Callable接口来创建Thread线程:其中,Callable接口(也只有一个方法)定义如下:

public interface Callable   
{   
    V call() throws Exception;   

步骤1:创建实现Callable接口的类SomeCallable(略);

步骤2:创建一个类对象:

      Callable oneCallable = new SomeCallable();

步骤3:由Callable创建一个FutureTask对象:

      FutureTask oneTask = new FutureTask(oneCallable);

      注释:FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了Future和Runnable接口。
步骤4:由FutureTask创建一个Thread对象:

       Thread oneThread = new Thread(oneTask);

步骤5:启动线程:

       oneThread.start();

至此,一个线程就创建完成了。

Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行

取消、****查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。

         Future类位于java.util.concurrent包下,它是一个接口:

public interface Future<V> {

boolean cancel(``boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

V get() throws InterruptedException, ExecutionException;

V get(``long timeout, TimeUnit unit)

throws InterruptedException, ExecutionException, TimeoutException;

}

   在Future接口中声明了5个方法,下面依次解释每个方法的作用:

  • cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数 mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若 mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论 mayInterruptIfRunning为true还是false,肯定返回true。

  • isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。

  • isDone方法表示任务是否已经完成,若任务完成,则返回true;

  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

  • get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

  也就是说Future提供了三种功能:

  1)判断任务是否完成;

  2)能够中断任务;

  3)能够获取任务执行结果。

  因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

Future使用示例:

package com.test.current;

import java.io.File;  

import java.io.FileInputStream;  

import java.io.IOException;  

import java.util.ArrayList;  

import java.util.Scanner;  

import java.util.concurrent.Callable;  

import java.util.concurrent.Future;  

import java.util.concurrent.FutureTask;  

public class FutureTest {  

public static void main(String[] args) {  

//指定目录和关键字

        String directory = "C:\\Program Files\\Java\\jdk1.6.0_29";  

        String keyword = "volatile";       

       //实现Callable接口的线程

        MatchCounter counter = new MatchCounter(new File(directory),keyword);  

        FutureTask task = new FutureTask(counter);  

        Thread t = new Thread(task);  

        t.start();  

try{  

            System.out.println(task.get() + "matching files");  

        }catch (Exception e) {  

            e.printStackTrace();  

        }  

    }  

}  

//这个线程用户向队列中添加文件

class MatchCounter implements Callable{  

private File directory;  

private String keyword;  

private int count;  

public static File DUMMY = new File("");//这个文件作为一个结束标记

public MatchCounter(File directory,String keyword){  

this.directory = directory;  

this.keyword = keyword;  

    }  

public Integer call(){  

        count = 0;  

try {  

            File[] files = directory.listFiles();  

            ArrayList<Future> results = new ArrayList<Future>();  

for (File file : files) {  

if(file.isDirectory()){  

                    MatchCounter counter = new MatchCounter(file, keyword);  

                    FutureTask task = new FutureTask(counter);  

                    results.add(task);  

                    Thread t = new Thread(task);  

                    t.start();  

                }else{  

if(search(file)){  

                        count++;  

                    }  

                }  

            }  

for(Future result:results){  

try{  

                    count += result.get();  

                }catch (Exception e) {  

                    e.printStackTrace();  

                }  

            }  

        } catch (Exception e) {  

            e.printStackTrace();  

        }  

return count;  

    }  

public boolean search(File file){  

try{  

            Scanner in = new Scanner(new FileInputStream(file));  

boolean found = false;  

while(!found && in.hasNextLine()){  

                String line = in.nextLine();  

if(line.contains(keyword)){  

                    found = true;  

                }  

            }  

            in.close();  

return found;  

        }catch (IOException e) {  

return false;  

        }  

    }  

}  

Futrue模式有个重大缺陷:当消费者工作得不够快的时候,它会阻塞住生产者线程,从而可能导致系统吞吐量的下降。所以不建议在高性能的服务端使用。

FutureTask

FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnbale又实现了Futrue这两个接口,

public class FutureTask implements RunnableFuture  

RunnableFuture

public interface RunnableFuture extends Runnable, Future {  

/**

     * Sets this Future to the result of its computation

     * unless it has been cancelled.

     */

void run();  

}  

另外它还可以包装Runnable和Callable, 由构造函数注入依赖。

public FutureTask(Callable callable) {  

if (callable == null)  

throw new NullPointerException();  

this.callable = callable;  

this.state = NEW;       // ensure visibility of callable

}  

public FutureTask(Runnable runnable, V result) {  

this.callable = Executors.callable(runnable, result);  

this.state = NEW;       // ensure visibility of callable

}  

可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :

public static  Callable callable(Runnable task, T result) {  

if (task == null)  

throw new NullPointerException();  

return new RunnableAdapter(task, result);  

}  

RunnableAdapter适配器

/**

 * A callable that runs given task and returns given result

 */

static final class RunnableAdapter implements Callable {  

final Runnable task;  

final T result;  

    RunnableAdapter(Runnable task, T result) {  

this.task = task;  

this.result = result;  

    }  

public T call() {  

        task.run();  

return result;  

    }  

}  

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。

并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、

Runnable,****又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。

简单示例

package com.effective.java.concurrent.task;  

import java.util.concurrent.Callable;  

import java.util.concurrent.ExecutionException;  

import java.util.concurrent.ExecutorService;  

import java.util.concurrent.Executors;  

import java.util.concurrent.Future;  

import java.util.concurrent.FutureTask;  

/**

 * 

 * @author mrsimple

 *

 */

public class RunnableFutureTask {  

/**

     * ExecutorService

     */

static ExecutorService mExecutor = Executors.newSingleThreadExecutor();  

/**

     * 

     * @param args

     */

public static void main(String[] args) {  

        runnableDemo();  

        futureDemo();  

    }  

/**

     * runnable, 无返回值

     */

static void runnableDemo() {  

new Thread(new Runnable() {  

@Override

public void run() {  

                System.out.println("runnable demo : " + fibc(20));  

            }  

        }).start();  

    }  

/**

     * 其中Runnable实现的是void run()方法,无返回值;Callable实现的是 V

     * call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下

     * ,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。

     */

static void futureDemo() {  

try {  

/**

             * 提交runnable则没有返回值, future没有数据

             */

            Future<?> result = mExecutor.submit(new Runnable() {  

@Override

public void run() {  

                    fibc(20);  

                }  

            });  

            System.out.println("future result from runnable : " + result.get());  

/**

             * 提交Callable, 有返回值, future中能够获取返回值

             */

            Future result2 = mExecutor.submit(new Callable() {  

@Override

public Integer call() throws Exception {  

return fibc(20);  

                }  

            });  

            System.out  

                    .println("future result from callable : " + result2.get());  

/**

             * FutureTask则是一个RunnableFuture,即实现了Runnbale又实现了Futrue这两个接口,

             * 另外它还可以包装Runnable(实际上会转换为Callable)和Callable

             * ,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行

             * ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。

             */

            FutureTask futureTask = new FutureTask(  

new Callable() {  

@Override

public Integer call() throws Exception {  

return fibc(20);  

                        }  

                    });  

// 提交futureTask

            mExecutor.submit(futureTask) ;  

            System.out.println("future result from futureTask : "

                    + futureTask.get());  

        } catch (InterruptedException e) {  

            e.printStackTrace();  

        } catch (ExecutionException e) {  

            e.printStackTrace();  

        }  

    }  

/**

     * 效率底下的斐波那契数列, 耗时的操作

     * 

     * @param num

     * @return

     */

static int fibc(int num) {  

if (num == 0) {  

return 0;  

        }  

if (num == 1) {  

return 1;  

        }  

return fibc(num - 1) + fibc(num - 2);  

    }  

}

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java多线程实现的三种方式
JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、继承Thread类实现多线程继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现
Wesley13 Wesley13
3年前
Java面试系列
实现多线程的方式继承Thread类,重写run方法,调用start方法启动线程实现Runnable接口,重写run方法,调用start方法启动线程实现Callable接口,重写call方法,并用FutureTask包装,在newThread中传入FutureTask,然后调用start方
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这