Callable接口与Runnable接口对比的主要优点是Callable接口可以通过Future获取返回值。但是Future接口调用get()方法取得结果时是阻塞的,如果调用Future对象的get()方法时任务尚未执行完,则调用get()方法时一直阻塞到此任务完成。如果前面的任务耗时很多,则后面的任务调用get()方法就呈阻塞状态,大大影响运行效率。主线程不能保证首先获得的是最先完成任务的返回值,这是Future的缺点。

public class MyCallable implements Callable<String> {
private int age; public MyCallable(int age) {
super();
this.age = age;
}
@Override
public String call() throws Exception {
TimeUnit.SECONDS.sleep(8);
return "返回值 年龄是:" + age;
} public static void main(String[] args) {
MyCallable myCallable = new MyCallable(22);
int corePoolSize = 2;
int maximumPoolSize = 3;
int keepAliveTime = 5;
TimeUnit unit = TimeUnit.SECONDS;
LinkedBlockingDeque<Runnable> workQueue = new LinkedBlockingDeque<Runnable>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
Future<String> future = threadPoolExecutor.submit(myCallable);
try {
System.out.println(System.currentTimeMillis());
String string = future.get();
System.out.println(string);
System.out.println(System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
}
}

打印结果如下:

1470904027660
返回值 年龄是:22
1470904035663

从打印结果看,可见get()方法具有阻塞的特性。

方法submit()不仅可以传入Callable对象,还可以传入Runnable对象,submit()方法支持有返回值和无返回值。

public class Run {
public static void main(String[] args) {
try {
Runnable runnable = new Runnable() { @Override
public void run() {
System.out.println("打印的信息");
}
};
ExecutorService executorService = Executors.newCachedThreadPool();
Future future = executorService.submit(runnable);
System.out.println(future.get() + " " + future.isDone());
} catch (Exception e) {
e.printStackTrace();
}
}
}

打印结果如下:

打印的信息
null true

方法isDone()无阻塞特性。


使用ExecutorService接口中的方法submit(Runnable, T result)
public class User {
private String username;
private String password;
//省略getter setter
} public class MyRunnable implements Runnable {
private User user;
public MyRunnable(User user) {
super();
this.user = user;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
user.setUsername("admin");
user.setPassword("123456");
}
} public class Main {
FutureTask task;
public static void main(String[] args) {
try {
User user = new User();
MyRunnable myRunnable = new MyRunnable(user);
int corePoolSize = 10;
int maximumPoolSize = 10;
int keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
LinkedBlockingDeque<Runnable> workQueue = new LinkedBlockingDeque<>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
Future<User> future = executor.submit(myRunnable, user);
System.out.println(System.currentTimeMillis());
System.out.println(user.getUsername() + "-" + user.getPassword());
user = future.get();
System.out.println(user.getUsername() + "-" + user.getPassword());
System.out.println(System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
}
}

控制台打印结果如下:

1470908214853
null-null
admin-123456
1470908216855

Java并发编程核心方法与框架-Future和Callable的使用的更多相关文章

  1. Java并发编程核心方法与框架-CountDownLatch的使用

    Java多线程编程中经常会碰到这样一种场景:某个线程需要等待一个或多个线程操作结束(或达到某种状态)才开始执行.比如裁判员需要等待运动员准备好后才发送开始指令,运动员要等裁判员发送开始指令后才开始比赛 ...

  2. Java并发编程核心方法与框架-Fork-Join分治编程(一)

    在JDK1.7版本中提供了Fork-Join并行执行任务框架,它的主要作用是把大任务分割成若干个小任务,再对每个小任务得到的结果进行汇总,这种开发方法也叫做分治编程,可以极大地利用CPU资源,提高任务 ...

  3. Java并发编程核心方法与框架-CompletionService的使用

    接口CompletionService的功能是以异步的方式一边生产新的任务,一边处理已完成任务的结果,这样可以将执行任务与处理任务分离.使用submit()执行任务,使用take取得已完成的任务,并按 ...

  4. Java并发编程核心方法与框架-TheadPoolExecutor的使用

    类ThreadPoolExecutor最常使用的构造方法是 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAli ...

  5. Java并发编程核心方法与框架-Semaphore的使用

    Semaphore中文含义是信号.信号系统,这个类的主要作用就是限制线程并发数量.如果不限制线程并发数量,CPU资源很快就会被耗尽,每个线程执行的任务会相当缓慢,因为CPU要把时间片分配给不同的线程对 ...

  6. Java并发编程核心方法与框架-ScheduledExecutorService的使用

    类SchedukedExecutorService的主要作用是可以将定时任务与线程池功能结合. 使用Callable延迟运行(有返回值) public class MyCallableA implem ...

  7. Java并发编程核心方法与框架-ExecutorService的使用

    在ThreadPoolExecutor中使用ExecutorService中的方法 方法invokeAny()和invokeAll()具有阻塞特性 方法invokeAny()取得第一个完成任务的结果值 ...

  8. Java并发编程核心方法与框架-Executors的使用

    合理利用线程池能够带来三个好处 降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 提高线程的可管理性.线程是稀 ...

  9. Java并发编程核心方法与框架-phaser的使用

    arriveAndAwaitAdvance()方法 arriveAndAwaitAdvance()作用是当前线程已经到达屏障,在此等待一段时间,等条件满足后继续向下一个屏障执行. public cla ...

随机推荐

  1. Windows 8.1 安装Ruby on Rails手记

    最近喜欢上了狂拽酷炫的Ruby 看了诸多文章都是Linux或Mac OS X环境配置,文章末尾还不忘把windows黑成一坨... 表示很无语.. 作为新世纪隐秘而强大的 .Net程序员 怎能脱离宇宙 ...

  2. java多线程synchronized底层实现

    一直想把这个特别重要的关键词的底层实现搞明白.(当然现在也没有完全明白,如果有错误以后修改这篇文章) 首先,这个关键词synchronize可以说是个语法糖,它的具体用法网上很多博客都讲的比较明了了. ...

  3. win10下安装Ubuntu出现win10无法进入的情况

    昨天晚上在win10上安装Ubuntu Kylin16.04系统,结果发现重启的时候进不去windows系统了,而且报的错误是 /EndEntire file path: /ACPI(a0341d,0 ...

  4. Value和Object的区别

    在使用NSMutableDictionary的时候经常会使用setValue forKey与setObject forKey,他们经常是可以交互使用的,代码中经常每一种的使用都有. 1,先看看setV ...

  5. Hibernate 执行原始SQL语句

    在hibernate中有时不需要用到表的映射,需要直接执行SQL语句. 其中sessionFactory在配置文件中配置,SSH详细配置见http://blog.csdn.NET/xumengxing ...

  6. SQL Server Code tips (持续更新)

    1.  表存在,查询语句也能执行,但是表名下面总是有条红线,说对象名无效 CTRL + SHIFT +R  刷新本地缓存就可以了 2. IDE (Integrated Development Envi ...

  7. 【BZOJ-4518】征途 DP + 斜率优化

    4518: [Sdoi2016]征途 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 230  Solved: 156[Submit][Status][ ...

  8. hdu 3089 约瑟夫环

    原来并不知道约瑟夫环还可以递推直接解orz 约瑟夫问题的递推公式: 设f[n]表示一共n个人,数到k出局,这样最后的winner (n个人从0开始标号,即0--n-1) f[n]=(f[n-1]+k) ...

  9. centos安装altas

    centos6.6 atlas2.2.1 atlas项目 https://github.com/Qihoo360/Atlas/releases yum -y install gcc make ncur ...

  10. zip压缩与解压缩示例

    范例: zip命令可以用来将文件压缩成为常用的zip格式.unzip命令则用来解压缩zip文件. 1. 我想把一个文件abc.txt和一个目录dir1压缩成为yasuo.zip: # zip -r y ...