SlideShare a Scribd company logo
1 of 73
Download to read offline
#JCConf
使用 Java 的 Future/Promise
API 來撰寫非同步程式
Koji Lin
JCConf 2015
#JCConf
使用 Java 的 Future/Promise
API 來撰寫非同步非阻塞程式
Koji Lin
JCConf 2015
About me
• Koji Lin
• @kojilin
• LINE Fukuoka, Japan
• 之前在 Cubie Inc.
• Android & iOS & 一些 Server side
大綱
• 非同步和非阻塞
• Java 8 前的方法
• j.u.c.CompletableFuture
什麼是非同步
• Asynchronous
• Not synchronous, or not
guaranteed to happen in the order
in which it appears in the code
from Playframework: Async, Reactive, Threads, Futures, ExecutionContexts
https://gist.github.com/sadache/4714280
什麼是非阻塞
• Non-blocking
• Doesn't cause the caller (Thread) to
be blocked waiting for a result,
from Playframework: Async, Reactive, Threads, Futures, ExecutionContexts
https://gist.github.com/sadache/4714280
為什麼?
• 有些工作很花時間
• 檔案讀寫
• 網路
• 加解密
• 圖片處理
壞處
• Web 服務,因為執行緒被長時間佔住,
提供的服務能處理的量降低
• 桌面或手機的應用,佔住執行緒會卡住
介面的反應,用戶體驗不佳
// 10 seconds
Image image1 = download(...);
render(image1);
// 12 seconds
Image image2 = download(...);
render(image2);
為什麼?
• 有些工作很花時間
• 想要更簡單的方式來控制流
程
Thread
• java.lang.Thread
• JDK 1.0
void downloadAsync(String url,
Consumer<Image> c) {
new Thread(() -> {
Image result = download(...);
c.accept(result);
}).start();
}
Thread 的缺點
• 常需配合用 synchronized, wait, notify
和 join
• 不同 Thread 間如何存取同一個變數
• 如何控管?
• 如何組合相依的工作
fetchDataAsync(data -> {
downloadAsync(data.avatar, image -> {
render(image);
});
});
new Thread(() -> {
final Data result = fetchData(...);
Image image = download(data.avatar);
Bitmap bitmap = decode(image);
...
}).start();
不易組合和再利用
• 組合各種非同步方法,寫起來會變成
callback hell
• 包一個外層的 Thread 執行
• 忘記包的話?
• 如何控制資源?
更複雜的組合
• 如果想要兩個任務結果都執行完畢
• 利用 Thread#join
• 如果只要任一個先取得該怎麼做?
• Thread#join(long millis) 和檢查結果
值
• 浪費一個 Thread 一直去做檢查
while(true) {
t1.join(1000);
if(t1Value != null) {
return t1Value;
}
t2.join(1000);
...
}
而且我們也不想再直接
使用 Thread API
Future
• java.util.concurrent.Future
• Java SE 5.0
• 一個等待結果的容器,讓我們可以需
要時嘗試去取得結果
ExecutorService service =
Executors.newCachedThreadPool();
Future<Image> f =
service.submit(() ->
downloadImage(...);
);
Future<Image> f = download(...);
Future<Image> f = download(...);
Future<Image> f = download(...);
... // 做點其他事情
Future<Image> f = download(...);
... // 做點其他事情
Image result = f.get();// 取得結果
阻塞
// 如果還沒有結果,會停住直到有結果
future.get();
阻塞
// 如果還沒有結果,會停住直到有結果
future.get();
future.get(5,
TimeUnit.SECONDS);
例外處理
try {
renderImage(future.get());
} catch(ExecutionException e) {
...
e.getCause();// 會是執行時丟的錯誤
}
其他方便的方法
future.cancel(boolean);
future.isCancelled();
future.isDone();
Future
• 從傳 callback 的方式,變成外部可以
自行再做處理
• 簡單易懂
• 只有 5 個方法
• 阻塞式的 API 來取得回傳
• 不易組合再利用
更複雜的組合
• 如果想要兩個任務結果都執行完畢
• 利用 Future#get
• 如果只要任一個先取得該怎麼做?
• Future#get(long, TimeUnit) 和檢查
結果值
• 浪費一個 Thread 一直去做檢查
CompletableFuture
• java.util.concurrent
• Java SE 8
• implements Future, CompletionStage
CF<String> cf = CompletableFuture
.completableFuture("Value");
CF<String> cf = CompletableFuture
.completableFuture("Value");
String result = cf.get();
CF<String> cf = CompletableFuture
.completableFuture("Value");
String result = cf.join();
CF<String> cf = CompletableFuture
.completableFuture("Value");
cf.thenAccept(
s -> System.out.println(s)
);
String load(){...}
...
CF<String> cf = CompletableFuture
.supplyAsync(() -> load());
CF<String> cf = CompletableFuture
.supplyAsync(() -> load(),
executorService);
CF<String> cf = ...;
CF<Integer> length = cf.thenApply(
data -> data.length()
);
cf.thenApplyAsync(
data -> data.length()
);
cf.thenApplyAsync(
data -> data.length(),
executorService
);
cf1 = cf.thenApplyAsync(...);
cf2 = cf.thenApplyAsync(...);
Task1
Task3
Task2
CF<String> cf = new
CompletableFuture();
cf.thenAccept(
s -> System.out.println(s)
);
CF<String> cf = new
CompletableFuture();
executor.submit(() -> {
String result = load();
cf.complete(result);
});
executor.submit(() -> {
try {
String result = load();
cf.complete(result);
} catch(Exception e) {
cf.completeExceptionally(e);
}
});
cf.whenComplete(
(String s, Throwable t) -> {
if(s != null)
System.out.println(s)
else
System.err.println(t)
}
);
How to change
existing code
CF<User> findUser(long uid){...};
CF<Image> download(User user){...};
CF<?> cf =
findUser(12L).thenApply(user ->
download(user)
);
CF<CF<Image>> cf =
findUser(12L).thenApply(user ->
download(user)
);
CF<File> cf = findUser(12L)
.thenCompose(
user -> download(user)
);
CF<File> cf = findUser(12L)
.thenCompose(
user -> download(user)
)
.thenCompose(
img -> save(img)
);
findUser(12L)
.thenApply(...)
.thenApply(...)// exception
.thenCompose(...)
.whenComplete(...);
allOf
CF<String> api1 = ...;
CF<String> api2 = ...;
CF<String> api3 = ...;
CF<Void> all =
CompletableFuture.allOf(api1,
api2, api3);
CF<List<String>> result =
all.thenApply(v ->
Arrays.asList(api1.get(),
api2.get(),
api3.get())
);
anyOf
CF<String> api1 = ...;
CF<String> api2 = ...;
CF<String> api3 = ...;
CF<Object> all =
CompletableFuture.anyOf(api1,
api2, api3);
App 中常見的行為
CF<User> findUser(String id);
CF<User> saveUSer(String id);
CF<Image> downloadAvatar(String id);
findUser(...)
.thenCompose(user ->
saveUser(user.id))
.thenCompose(user ->
downloadAvatar(user.id))
.thenAccept(img ->
render(img));
同時多 key 查詢
CF<Value> executeQuery(String id);
List<CF<Value>> queries =
ids.stream()
.map(id -> executeQuery(id))
.collect(toList());
//using allOf to let
//List<CF<Value>> -> CF<List<Value>>
CF<Void> all =
CF.allOf(queries.toArray());
CF<List<Value>> result =
all.thenApply(v ->
queries.stream()
.map(q -> q.join())
.collect(toList)
);
getOrderFromNetwork
getOrderFromDb
listProducts
getShipInfo
Data Flow
sendMail
• 事件驅動 (event driven)
• 容易組合 (easy to compose)
• 控制權可以回給呼叫者
• 減少 thread 的浪費
優點
• Future/Promise 的混合
• 不少語言實作是分開的
• 爆多的方法數量
• 60+
缺點
Demo
• CompletableFuture#cancel
• 不能取消正在執行的工作
• 盡量使用 Async 語尾的 API
注意
findUser
listArticles
listFriend
支援非同步的 WEB 框架
• Servlet 3.0 AsyncContext
• Spring Framework
• Controller 的回傳直接用 CompletableFuture
• Play Framework
• Asynchronous web framework
• play.libs.F.Promise
Web application
• 該不該用處理 http 的 thread 做事?
• Tomcat 有 max-threads 設定
• Play 本來就是 http 跟 worker 分離
• 每個要求的工作時間不一定相同
• 花多少時間?佔多少比例?
• 花時間的工作有沒有資源存取上限?
Simple Test
• Job: 1500ms ~ 30%, 100ms ~ 70%
• 無處理上限
• Tomcat max-threads 200
• ab -n 1000 -c 400
• Async ~375 requests/second
• Sync ~300 requests/second
Simple Test
• Job: 1500ms ~ 50%, 100ms ~ 50%
• 一次只能處理 30 件 1500 ms 的工作
• Async ~36 requests/second
• 50% < 2000ms
• Sync ~39 requests/second
• 50% < 5900ms
Android 不支援
Java 8 API
• Guava
• ListenableFuture
• RxJava
• Reactive Programming
• Bolts-Android
• Lambda !?
Reactive Programming
• Data flow
• Propagation of change
• Flow in Java 9 ?
Q&A

More Related Content

What's hot

DevOps on AWS - Building Systems to Deliver Faster
DevOps on AWS - Building Systems to Deliver FasterDevOps on AWS - Building Systems to Deliver Faster
DevOps on AWS - Building Systems to Deliver FasterAmazon Web Services
 
Chaos Engineering for Docker
Chaos Engineering for DockerChaos Engineering for Docker
Chaos Engineering for DockerAlexei Ledenev
 
CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...
CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...
CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...Edureka!
 
Principles of Technology Leadership
Principles of Technology LeadershipPrinciples of Technology Leadership
Principles of Technology Leadershipbcantrill
 
日本で DevOps を ロケットスタートする方法
日本で DevOps を  ロケットスタートする方法日本で DevOps を  ロケットスタートする方法
日本で DevOps を ロケットスタートする方法Puppet
 
k8s practice 2023.pptx
k8s practice 2023.pptxk8s practice 2023.pptx
k8s practice 2023.pptxwonyong hwang
 
Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015Jose Luis Martínez
 
Fundamentals of DevOps and CI/CD
Fundamentals of DevOps and CI/CDFundamentals of DevOps and CI/CD
Fundamentals of DevOps and CI/CDBatyr Nuryyev
 
Building an Enterprise-scale DevSecOps Infrastructure: Lessons Learned
Building an Enterprise-scale DevSecOps Infrastructure: Lessons LearnedBuilding an Enterprise-scale DevSecOps Infrastructure: Lessons Learned
Building an Enterprise-scale DevSecOps Infrastructure: Lessons LearnedPrateek Mishra
 
Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)
Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)
Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)Kai Wähner
 
A New Perspective on Resource-Level Cloud Forensics
A New Perspective on Resource-Level Cloud ForensicsA New Perspective on Resource-Level Cloud Forensics
A New Perspective on Resource-Level Cloud ForensicsChristopher Doman
 
Taking AppSec to 11: AppSec Pipeline, DevOps and Making Things Better
Taking AppSec to 11: AppSec Pipeline, DevOps and Making Things BetterTaking AppSec to 11: AppSec Pipeline, DevOps and Making Things Better
Taking AppSec to 11: AppSec Pipeline, DevOps and Making Things BetterMatt Tesauro
 
IBM Cloud Pak for Integration 2020.2.1 installation
IBM Cloud Pak for Integration 2020.2.1 installation IBM Cloud Pak for Integration 2020.2.1 installation
IBM Cloud Pak for Integration 2020.2.1 installation khawkwf
 
Azure Boards.pptx
Azure Boards.pptxAzure Boards.pptx
Azure Boards.pptxNitin Sethi
 
Containers: The What, Why, and How
Containers: The What, Why, and HowContainers: The What, Why, and How
Containers: The What, Why, and HowSneha Inguva
 

What's hot (20)

DevOps on AWS - Building Systems to Deliver Faster
DevOps on AWS - Building Systems to Deliver FasterDevOps on AWS - Building Systems to Deliver Faster
DevOps on AWS - Building Systems to Deliver Faster
 
CI/CD on AWS
CI/CD on AWSCI/CD on AWS
CI/CD on AWS
 
Chaos Engineering for Docker
Chaos Engineering for DockerChaos Engineering for Docker
Chaos Engineering for Docker
 
CICD with Jenkins
CICD with JenkinsCICD with Jenkins
CICD with Jenkins
 
CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...
CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...
CI CD Pipeline Using Jenkins | Continuous Integration and Deployment | DevOps...
 
Principles of Technology Leadership
Principles of Technology LeadershipPrinciples of Technology Leadership
Principles of Technology Leadership
 
日本で DevOps を ロケットスタートする方法
日本で DevOps を  ロケットスタートする方法日本で DevOps を  ロケットスタートする方法
日本で DevOps を ロケットスタートする方法
 
Istio
Istio Istio
Istio
 
k8s practice 2023.pptx
k8s practice 2023.pptxk8s practice 2023.pptx
k8s practice 2023.pptx
 
Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015
 
Fundamentals of DevOps and CI/CD
Fundamentals of DevOps and CI/CDFundamentals of DevOps and CI/CD
Fundamentals of DevOps and CI/CD
 
Building an Enterprise-scale DevSecOps Infrastructure: Lessons Learned
Building an Enterprise-scale DevSecOps Infrastructure: Lessons LearnedBuilding an Enterprise-scale DevSecOps Infrastructure: Lessons Learned
Building an Enterprise-scale DevSecOps Infrastructure: Lessons Learned
 
Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)
Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)
Microservices - Death of the Enterprise Service Bus (ESB)? (Update 2016)
 
A New Perspective on Resource-Level Cloud Forensics
A New Perspective on Resource-Level Cloud ForensicsA New Perspective on Resource-Level Cloud Forensics
A New Perspective on Resource-Level Cloud Forensics
 
Custom JSF components
Custom JSF componentsCustom JSF components
Custom JSF components
 
Taking AppSec to 11: AppSec Pipeline, DevOps and Making Things Better
Taking AppSec to 11: AppSec Pipeline, DevOps and Making Things BetterTaking AppSec to 11: AppSec Pipeline, DevOps and Making Things Better
Taking AppSec to 11: AppSec Pipeline, DevOps and Making Things Better
 
IBM Cloud Pak for Integration 2020.2.1 installation
IBM Cloud Pak for Integration 2020.2.1 installation IBM Cloud Pak for Integration 2020.2.1 installation
IBM Cloud Pak for Integration 2020.2.1 installation
 
Challenges of Kubernetes On-premise Deployment
Challenges of Kubernetes On-premise DeploymentChallenges of Kubernetes On-premise Deployment
Challenges of Kubernetes On-premise Deployment
 
Azure Boards.pptx
Azure Boards.pptxAzure Boards.pptx
Azure Boards.pptx
 
Containers: The What, Why, and How
Containers: The What, Why, and HowContainers: The What, Why, and How
Containers: The What, Why, and How
 

Viewers also liked

Using armeria to write your RPC
Using armeria to write your RPCUsing armeria to write your RPC
Using armeria to write your RPCkoji lin
 
Writing and using Hamcrest Matchers
Writing and using Hamcrest MatchersWriting and using Hamcrest Matchers
Writing and using Hamcrest MatchersShai Yallin
 
Java8 time
Java8 timeJava8 time
Java8 timekoji lin
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesHaim Yadid
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuturekoji lin
 
TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用Mark Chang
 
TypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript ComparisonTypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript ComparisonHaim Michael
 
TensorFlow 深度學習快速上手班--深度學習
 TensorFlow 深度學習快速上手班--深度學習 TensorFlow 深度學習快速上手班--深度學習
TensorFlow 深度學習快速上手班--深度學習Mark Chang
 
TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習Mark Chang
 
TensorFlow 深度學習講座
TensorFlow 深度學習講座TensorFlow 深度學習講座
TensorFlow 深度學習講座Mark Chang
 

Viewers also liked (13)

Using armeria to write your RPC
Using armeria to write your RPCUsing armeria to write your RPC
Using armeria to write your RPC
 
Monoids
MonoidsMonoids
Monoids
 
Writing and using Hamcrest Matchers
Writing and using Hamcrest MatchersWriting and using Hamcrest Matchers
Writing and using Hamcrest Matchers
 
Java8 time
Java8 timeJava8 time
Java8 time
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFutures
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
 
TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用
 
TypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript ComparisonTypeScript, Dart, CoffeeScript and JavaScript Comparison
TypeScript, Dart, CoffeeScript and JavaScript Comparison
 
TensorFlow 深度學習快速上手班--深度學習
 TensorFlow 深度學習快速上手班--深度學習 TensorFlow 深度學習快速上手班--深度學習
TensorFlow 深度學習快速上手班--深度學習
 
TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習TensorFlow 深度學習快速上手班--機器學習
TensorFlow 深度學習快速上手班--機器學習
 
TensorFlow 深度學習講座
TensorFlow 深度學習講座TensorFlow 深度學習講座
TensorFlow 深度學習講座
 
Think Async in Java 8
Think Async in Java 8Think Async in Java 8
Think Async in Java 8
 
TENSORFLOW深度學習講座講義(很硬的課程)
TENSORFLOW深度學習講座講義(很硬的課程)TENSORFLOW深度學習講座講義(很硬的課程)
TENSORFLOW深度學習講座講義(很硬的課程)
 

Similar to 使用 Java 上的 future/promise API

Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoloadjay li
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层yiditushe
 
Graphic programming in js
Graphic programming in jsGraphic programming in js
Graphic programming in jsjay li
 
Java script closures
Java script closuresJava script closures
Java script closuresskywalker1114
 
Java script closures
Java script closuresJava script closures
Java script closuresskywalker1114
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用Shengyou Fan
 
Symfony簡介
Symfony簡介Symfony簡介
Symfony簡介Ricky Su
 
廖雪峰 Saa s ovp
廖雪峰 Saa s ovp廖雪峰 Saa s ovp
廖雪峰 Saa s ovpdrewz lin
 
AngularJS training in Luster
AngularJS training in LusterAngularJS training in Luster
AngularJS training in LusterJason Chung
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计yiming he
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式Shengyou Fan
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非Tony Deng
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践taobao.com
 
Dive into kissy
Dive into kissyDive into kissy
Dive into kissyjay li
 
Koa 正在等一個人
Koa 正在等一個人Koa 正在等一個人
Koa 正在等一個人Fred Chien
 

Similar to 使用 Java 上的 future/promise API (20)

Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
 
I os 07
I os 07I os 07
I os 07
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层
 
Graphic programming in js
Graphic programming in jsGraphic programming in js
Graphic programming in js
 
I os 16
I os 16I os 16
I os 16
 
Java script closures
Java script closuresJava script closures
Java script closures
 
Java script closures
Java script closuresJava script closures
Java script closures
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
 
Symfony簡介
Symfony簡介Symfony簡介
Symfony簡介
 
YUI 3 菜鳥救星
YUI 3 菜鳥救星YUI 3 菜鳥救星
YUI 3 菜鳥救星
 
廖雪峰 Saa s ovp
廖雪峰 Saa s ovp廖雪峰 Saa s ovp
廖雪峰 Saa s ovp
 
AngularJS training in Luster
AngularJS training in LusterAngularJS training in Luster
AngularJS training in Luster
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践
 
Dive into kissy
Dive into kissyDive into kissy
Dive into kissy
 
Koa 正在等一個人
Koa 正在等一個人Koa 正在等一個人
Koa 正在等一個人
 
OSGi Small Lab
OSGi Small LabOSGi Small Lab
OSGi Small Lab
 

More from koji lin

サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよkoji lin
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code genkoji lin
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Androidkoji lin
 
docker intro
docker introdocker intro
docker introkoji lin
 
Java8 stream
Java8 streamJava8 stream
Java8 streamkoji lin
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambdakoji lin
 
Raspberry Pi with Java
Raspberry Pi with JavaRaspberry Pi with Java
Raspberry Pi with Javakoji lin
 
Services you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile appServices you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile appkoji lin
 
Programming with Threads in Java
Programming with Threads in JavaProgramming with Threads in Java
Programming with Threads in Javakoji lin
 
山頂洞人日記 - 回歸到最純樸的開發
山頂洞人日記 -  回歸到最純樸的開發山頂洞人日記 -  回歸到最純樸的開發
山頂洞人日記 - 回歸到最純樸的開發koji lin
 
Android Location-based應用開發分享
Android Location-based應用開發分享Android Location-based應用開發分享
Android Location-based應用開發分享koji lin
 

More from koji lin (15)

サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよ
 
G1GC
G1GCG1GC
G1GC
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
 
Jcconf
JcconfJcconf
Jcconf
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Android
 
docker intro
docker introdocker intro
docker intro
 
Java8 stream
Java8 streamJava8 stream
Java8 stream
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambda
 
Idea13
Idea13Idea13
Idea13
 
Raspberry Pi with Java
Raspberry Pi with JavaRaspberry Pi with Java
Raspberry Pi with Java
 
Services you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile appServices you can use to monitor and analyze mobile app
Services you can use to monitor and analyze mobile app
 
Programming with Threads in Java
Programming with Threads in JavaProgramming with Threads in Java
Programming with Threads in Java
 
JQuery
JQueryJQuery
JQuery
 
山頂洞人日記 - 回歸到最純樸的開發
山頂洞人日記 -  回歸到最純樸的開發山頂洞人日記 -  回歸到最純樸的開發
山頂洞人日記 - 回歸到最純樸的開發
 
Android Location-based應用開發分享
Android Location-based應用開發分享Android Location-based應用開發分享
Android Location-based應用開發分享
 

使用 Java 上的 future/promise API