Java 调用线程如何周期性地等待ScheduledExecutorService下的任务完成作业
我有一个要求,比如在进行http调用后,必须每45分钟更新一次值Java 调用线程如何周期性地等待ScheduledExecutorService下的任务完成作业,java,multithreading,executorservice,scheduledexecutorservice,Java,Multithreading,Executorservice,Scheduledexecutorservice,我有一个要求,比如在进行http调用后,必须每45分钟更新一次值 import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEnt
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class TokenManagerRunnable implements Runnable{
String token;
public String fetchToken() {
return this.token;
}
@Override
public void run() {
String result = "";
HttpPost post = new HttpPost("https://login.microsoftonline.com/{{TenentId}}/oauth2/token");
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("grant_type", "client_credentials"));
urlParameters.add(new BasicNameValuePair("client_id", "some client id"));
urlParameters.add(new BasicNameValuePair("client_secret", "some secret id"));
urlParameters.add(new BasicNameValuePair("resource", "https://database.windows.net"));
try {
post.setEntity(new UrlEncodedFormEntity(urlParameters));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post)){
result = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ObjectNode node;
try {
node = new ObjectMapper().readValue(result, ObjectNode.class);
System.out.println(result);
if (node.has("access_token")) {
result = node.get("access_token").toString();
}
System.out.println(result);
System.out.println(result.substring(1, result.length()-1));
//updating the token
this.token = result.substring(1, result.length()-1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
tokenManagerRunnable.fetchToken()带来null,因为tokenManagerRunnable类尚未执行
我们如何实现等待ScheduledExecutorService完成任务,以便每隔45分钟从tokenManagerRunnable.fetchToken()而不是null获取值并在数据源中设置新值
有什么想法吗?你已经知道,这是一个同步问题。 同步线程的方法主要有两种:
- 同步使用join
- 异步使用回调
//导入[…]
公共类TokenManagerRunnable实现可运行{
专用最终SQLServerDataSource ds;
/**
*使用数据源触发令牌持久性的新构造函数
*关于检索。
*@param-ds
*/
公共TokenManagerRunnable(SQLServerDataSource ds){
这是1.ds=ds;
}
/**
*检索时在数据源上持久化标记的新方法。
*@param令牌
*/
私有void setToken(字符串令牌){
System.out.println(“获取令牌----”+令牌);
this.ds.setAccessToken(令牌);
}
@凌驾
公开募捐{
//检索[……]
试一试{
//解析[…]
//更新令牌
this.setToken(result.substring(1,result.length()-1));
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
如您所见,运行程序不需要任何状态,因为它将直接将结果流式传输到数据源。
您只需在构建时向运行程序提供此数据源
SQLServerDataSource ds=newsqlserverdatasource();
TokenManagerRunnable TokenManagerRunnable=新的TokenManagerRunnable(ds);
//在此运行调用结束时同步运行1次
//将设置令牌
tokenManagerRunnable.run();
//从现在开始,每45分钟计划一次令牌刷新
ScheduledExecutorService sches=执行者。newScheduledThreadPool(1);
Schedule.scheduleWithFixedDelay(tokenManagerRunnable,0,45,时间单位:分钟);
//使用令牌[…]
编辑
正如您在评论中所述,您需要先执行Runnable
,然后才能联系数据库。
您需要同步执行此操作,或者在单独的线程中添加下面的代码,具体取决于您打算对应用程序执行的操作。下面的问题是您的应用程序是否依赖于此初始化
事实上,您可以调用run()
方法,而无需将其放入线程中,这样就可以同步运行令牌更新。
这意味着您需要调用
tokenManagerRunnable.run()在计划线程执行中启动自动刷新之前,同步执行代码>。如果我没有弄错您的问题,您可以使用CompletableFuture
。您在CompletableFuture
中包装token
,调度线程完成它。由于CompletableFuture
是一个Future
,其他线程可以等待结果
下面是一个基本的实现,演示了该机制
import java.util.concurrent.CompletableFuture;
班长{
静态CompletableFuture令牌=新的CompletableFuture();
公共静态void main(字符串[]args){
新线程(()->{
对于(int i=0;i<100_000;i++){
Math.log(Math.sqrt(i));
如果(i%10\u 000\u 000==0){
System.out.println(“做事”);
}
}
标记。完成(“结果”);
}).start();
String result=token.join();//等待直到设置了token并获取它
System.out.println(“got”+结果);
}
}
请记住,在获得结果后,您必须分配一个新的CompletableFuture
。这是因为它们只能完成一次
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.util.ArrayList;
import java.util.List;
public class AzureServicePrincipleTokenManager implements Runnable {
SQLServerDataSource ds ;
String secret;
String clientId;
String tenetId;
static final String RESOURCE = "https://database.windows.net";
static final String ENDPOINT = "https://login.microsoftonline.com/";
static final String GRANT_TYPE = "client_credentials";
boolean confirmTokenFlag=false;
private static Log logger = LogFactory.getLog( "AzureServicePrincipleTokenManager" );
public AzureServicePrincipleTokenManager(SQLServerDataSource ds, String tenetId, String clientId, String secret) {
this.ds = ds;
this.secret = secret;
this.clientId = clientId;
this.tenetId = tenetId;
}
public boolean getConfirmTokenFlag(){
return this.confirmTokenFlag;
}
private void setAccessToken(String token){
this.ds.setAccessToken(token);
}
@Override
public void run() {
logger.info("Fetching Service Principle accessToken");
String result = "";
HttpPost post = new HttpPost(ENDPOINT+this.tenetId+"/oauth2/token");
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("grant_type", GRANT_TYPE));
urlParameters.add(new BasicNameValuePair("client_id", this.clientId));
urlParameters.add(new BasicNameValuePair("client_secret", this.secret));
urlParameters.add(new BasicNameValuePair("resource", RESOURCE));
try{
post.setEntity(new UrlEncodedFormEntity(urlParameters));
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post);
result = EntityUtils.toString(response.getEntity());
ObjectNode node = new ObjectMapper().readValue(result, ObjectNode.class);
if (node.has("access_token")) {
result = node.get("access_token").toString();
}
}catch (Exception ex){
logger.error(ex.getMessage(),ex);
}
this.setAccessToken(result.substring(1, result.length()-1));
confirmTokenFlag=true;
logger.info("set confirmTokenFlag true");
}
}
即使任务没有完成,我的调用线程仍在继续,我也使用了您的代码更改。我已经更新了这个问题,这样你就可以清楚地了解我的问题所在。因此,你需要第一次同步执行,我相应地用编辑部分更新了答案:)如果你已经解决了自己的问题,那么你可以将你的答案标记为解决方案。那么帖子就不会永远处于找不到解决方案的状态。
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.util.ArrayList;
import java.util.List;
public class AzureServicePrincipleTokenManager implements Runnable {
SQLServerDataSource ds ;
String secret;
String clientId;
String tenetId;
static final String RESOURCE = "https://database.windows.net";
static final String ENDPOINT = "https://login.microsoftonline.com/";
static final String GRANT_TYPE = "client_credentials";
boolean confirmTokenFlag=false;
private static Log logger = LogFactory.getLog( "AzureServicePrincipleTokenManager" );
public AzureServicePrincipleTokenManager(SQLServerDataSource ds, String tenetId, String clientId, String secret) {
this.ds = ds;
this.secret = secret;
this.clientId = clientId;
this.tenetId = tenetId;
}
public boolean getConfirmTokenFlag(){
return this.confirmTokenFlag;
}
private void setAccessToken(String token){
this.ds.setAccessToken(token);
}
@Override
public void run() {
logger.info("Fetching Service Principle accessToken");
String result = "";
HttpPost post = new HttpPost(ENDPOINT+this.tenetId+"/oauth2/token");
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("grant_type", GRANT_TYPE));
urlParameters.add(new BasicNameValuePair("client_id", this.clientId));
urlParameters.add(new BasicNameValuePair("client_secret", this.secret));
urlParameters.add(new BasicNameValuePair("resource", RESOURCE));
try{
post.setEntity(new UrlEncodedFormEntity(urlParameters));
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post);
result = EntityUtils.toString(response.getEntity());
ObjectNode node = new ObjectMapper().readValue(result, ObjectNode.class);
if (node.has("access_token")) {
result = node.get("access_token").toString();
}
}catch (Exception ex){
logger.error(ex.getMessage(),ex);
}
this.setAccessToken(result.substring(1, result.length()-1));
confirmTokenFlag=true;
logger.info("set confirmTokenFlag true");
}
}
SQLServerDataSource ds = new SQLServerDataSource();
AzureServicePrincipleTokenManager azureServicePrincipleTokenManager = new AzureServicePrincipleTokenManager(ds,"your tenentID","your clientID","your secret");
ScheduledExecutorService sches = Executors.newScheduledThreadPool(1);
sches.scheduleWithFixedDelay(azureServicePrincipleTokenManager, 0, 45, TimeUnit.MINUTES);
logger.info("----ExecuterService started the Runnable task");
while (azureServicePrincipleTokenManager.getConfirmTokenFlag()!=true){
ds.getAccessToken(); //I wonder If i leave while body balnk it never become true. so intentionally i'm calling ds.getAccessToken();
}
logger.info("----get the token after settingup "+ds.getAccessToken());