我有两个线程在Java程序中并行运行,如下所示:
// Threading
new Thread(new Runnable() {
@Override
public void run() {
try {
gpTableCount = getGpTableCount();
} catch (SQLException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
hiveTableCount = getHiveTableCount();
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
while(!(gpTableCount != null && gpTableCount.size() > 0 && hiveTableCount != null && hiveTableCount.size() > 0)) {
Thread.sleep(5000);
}
// Threading
它们两者具有相同的功能。下面是来自getHiveTableCount()的代码。另一种方法与下面的方法略有不同(一两行),但是功能保持不变。
public Map<String, String> getHiveTableCount() throws IOException, SQLException {
hiveDataMap = new HashMap<String, String>();
hiveTableErrs = new HashMap<String, String>();
Iterator<String> hiveIterator = filteredList.iterator();
Connection hiveConnection = DbManager.getHiveConnection();
PreparedStatement hive_pstmnt = null;
String hiveExcpnMsg;
String ssn;
String hiveMaxUpdTms;
Long hiveCount;
String gpHiveRec;
String[] hiveArray;
String[] hiveDetails;
String hiveQuery;
while(hiveIterator.hasNext()) {
gpHiveRec = hiveIterator.next();
hiveArray = gpHiveRec.split(",");
hiveDetails = hiveArray[1].split("\\.");
hiveQuery = "select '" + hiveDetails[1] + "' as TableName, count(*) as Count, source_system_name, max(xx_last_update_tms) from " + hiveArray[1] + " where source_system_name='" + hiveArray[2] + "' group by source_system_name";
try {
hive_pstmnt = hiveConnection.prepareStatement(hiveQuery);
ResultSet hiveCountRs = hive_pstmnt.executeQuery();
while(hiveCountRs.next()) {
hiveCount = hiveCountRs.getLong(2);
ssn = hiveCountRs.getString(3);
hiveMaxUpdTms = hiveCountRs.getTimestamp(4).toString();
hiveDataMap.put(hiveDetails[1] + "," + ssn, hiveCount + "," + hiveMaxUpdTms);
}
} catch(org.postgresql.util.PSQLException e) {
hiveExcpnMsg = e.getMessage();
hiveTableErrs.put(hiveDetails[1] + ": for the SSN: " + hiveArray[2], hiveExcpnMsg + "\n");
} catch(SQLException e) {
hiveExcpnMsg = e.getMessage();
hiveTableErrs.put(hiveDetails[1] + ": for the SSN: " + hiveArray[2], hiveExcpnMsg + "\n");
} catch(Exception e) {
hiveExcpnMsg = e.getMessage();
hiveTableErrs.put(hiveDetails[1] + ": for the SSN: " + hiveArray[2], hiveExcpnMsg + "\n");
}
}
return hiveDataMap;
}
这两个线程同时运行。我最近在网上阅读了以下内容:
未来类代表异步计算的未来结果 –结果将最终出现在将来 处理完成。
我从理论上理解了该概念,但是我不知道如何为上述相同代码应用java.util.concurrent.Future api,而不是显式创建线程。
谁能让我知道如何在方法上实现多线程:getGpTableCount() & getHiveTableCount
使用java.util.concurrent.Future api而不是创建线程来创建新线程,例如new Thread(new Runnable()?
答案 0 :(得分:1)
您正在使用Runnable
接口提交任务,该接口不允许线程在计算结束时返回值(并导致您使用共享变量-gpTableCount
和{{ 1}})。
hiveTableCount
接口是后来的添加,它使您的任务可以返回值(在您的情况下为Callable
)。
作为直接使用线程的替代方法,Concurrency API引入了Map<String, String>
作为高级对象,该对象管理线程池并能够异步执行任务。
将ExecutorService
类型的任务提交给Callable
时,您期望任务会产生一个值,但是由于提交点和计算的末尾没有耦合,因此{{ 1}}将返回ExecutorService
,该值可让您获取此值,如果该值不可用,则阻止。因此,ExecutorService
可用于在不同线程之间进行同步。
作为Future
的替代方法,您还可以查看Future
的实现方式ExecutorService
:
此类提供了
FutureTask<V>
的基本实现,其中包含启动和取消计算,查询以查看计算是否完成以及检索计算结果的方法FutureTask可用于包装Callable或Runnable对象。
答案 1 :(得分:0)
首先,创建最适合您需求的执行程序服务,例如:
ExecutorService ex = Executors.newFixedThreadPool(2);
(有关执行人的更多信息:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html)
然后将Runnable对象更改为Callable,该对象类似于runnable,但是返回一个值(有关callable的更多信息:https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/Callable.html):
Callable<Map<String, String>> callable1 = // your Callable class
Type参数应与您要作为结果返回的类型相同。
接下来创建您的任务列表:
List<Callable<Map<String, String>>> tasks = new LinkedList<>();
tasks.add(callable1);
tasks.add(callable2);
并执行它们:
Future<Map<String, String>> results = ex.invokeAll(tasks);
以上方法在所有任务完成后返回(如果我正确理解了您的情况,这就是您想要实现的目标),但是完成的任务可能已正常终止或引发异常而终止。
最后关闭执行程序服务:
ex.shutdown();
答案 2 :(得分:0)
如果您使用的是Java 8+,则可以使用CompletableFuture.supplyAsync
来简短地表示,例如:
import static java.util.concurrent.CompletableFuture.supplyAsync;
.....
Future<Map<String, String>> f= supplyAsync(()->{
try{
return getHiveTableCount();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
CompletableFuture.supplyAsync
将在默认情况下使用ForkJoinPool.commonPool()
运行它,如果您要使用自己的参数,则还有一个重叠之处,那就是在参数中使用Executor
:
public class CompletableFuture<T>
extends Object
implements Future<T>, CompletionStage<T>
并且有。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor)