从 Callable 类调用常用方法的最佳方式?

问题描述 投票:0回答:1

我使用 Callable 类型的 java 类(最多并行 200 个),它调用工具类的方法(集中公共方法),我注意到如果这个方法不是“同步”的,我会收到错误。 我尝试过将此方法移至 Callable 类,但问题仍然存在。

使用“同步”,它可以工作,但我担心此设置会降低性能,因为并行启动的任务不能完全独立,并且会相互减慢,而不是以最大速度运行。

实现这一点的最佳方法是什么?

下面(简化)摘自我的代码。如果没有“同步”,只要数据比较不处理日期,似乎就不会出现错误。但是,如果该方法比较日期(实际上,更准确地说,是 java.util.Date 和 Timestamp 的混合,我将其转换为日期,然后转换为字符串),则会出现错误。但该方法工作正常,因为一旦我切换到同步,就没有错误......

public class CompareTableTF {
...
    public void compareTable(...) {
    ...
        while (...) {
        try {
            myTask = new CompareTableTask(...);
            completion.submit(myTask);
        }
        catch (InterruptedException | ExecutionException e) {...}
        ...
    }
}
public class CompareTableTask implements Callable<Integer> {
    private List<Object> row1;

    public CompareTableTask(List<Object> row1) { 
        this.row1=row1;
    }

    @Override
    public Integer call() {
        int result=1;
        List<Object> row2=getRowToCompare(...);
        if (isEqual(row2)) {
            result=0;
        }
        return result;
    }

    private boolean isEqual(List<Object> row2) {
        ...
        for (int i=0; i<n; i++) {
            if (! Tools.areEqual(row1.get(i), row2.get(i))) return false;
        }
        return true;
    }
public class Tools {
    private final static SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");

    ...
    public synchronized static boolean areEqual(Object obj1, Object obj2) {
        String sObj1, sObj2;
        Double dObj1, dObj2;
        Date dtObj1, dtObj2;
        boolean resultat = true;
        
        // Check if one only is empty
        ...
        // Compare as objects
        if (!obj1.equals(obj2)) {

        // if differents, compare as strings
            sObj1=obj1.toString();
            sObj2=obj2.toString();
            if (!sObj1.equals(sObj2)) {

            // if differents, verify if are instanceof java.util.Date, convert them to strings, compare as strings
            if (obj1 instanceof Date && obj2 instanceof Date) {
                if (obj1 instanceof Timestamp) {dtObj1 = new Date(((Timestamp) obj1).getTime());} else {dtObj1 = (Date) obj1;}
                if (obj2 instanceof Timestamp) {dtObj2 = new Date(((Timestamp) obj2).getTime());} else {dtObj2 = (Date) obj2;}
                sObj1 = dateTimeFormat.format(dtObj1);
                sObj2 = dateTimeFormat.format(dtObj2);
                result = sObj1.equals(sObj2);
            }
            else {
                // if differents (and not date), last compare as Double
                resultat=false;
                try {
                    dObj1 = new Double(sObj1);
                    dObj2 = new Double(sObj2);
                    if (dObj1.equals(dObj2)) {
                        resultat=true;
                    }
                }
                catch (NumberFormatException e) {
                }
            }
        }
        return result;
    }
}
java date timestamp synchronized callable
1个回答
5
投票

JDBC 的 API 是半破损的,因为它保证了基于

getTimestamp
setTimestamp
/
java.sql.Timestamp
的存在,以及基于
setDate
getDate
/
java.sql.Date
的存在。不幸的是,这两种类型都扩展了
java.util.Date
;所有这些类型都已损坏。

JDBC 作为一种设计,决定为每个相关数据类型创建

getFoobar()
方法不再是一个可扩展的主张。新的 JDBC 方式是使用任意类型的 get 和 set 方法:

try (ResultSet rs = ....) {
  LocalDate ld = rs.getObject(1, LocalDate.Class); // right
  java.sql.Date d = rs.getDate(1); // wrong
}

LocalDate 和 OffsetDateTime 都保证可以工作。 LocalDateTime 和 ZonedDateTime 取决于您的 JDBC 实现。例如,Postgres JDBC 驱动程序支持

LocalDate
LocalTime
LocalDateTime
OffsetDateTime
。分别是
DATE
TIME WITHOUT TIME ZONE
TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP WITH TIME ZONE
的 Java 等效项。
TIME
TIMESTAMP
without time zone 变体的别名。

对于PreparedStatements,

prepStatement.setObject(1, localDateInstance)
是它的完成方式(没有
setLocalDate
方法,也永远不会有——对于所有与数据库交互相关的未来类型,JDBC设计已经采用了
setObject
)。

至关重要的是,来自

java.time
包的所有这些类都没有被破坏,并且与数据库的工作方式相匹配,即直接存储人类计算术语。例如。 DATE 在数据库中存储 3 个数字:年、月和日。
java.time.LocalTime
的工作原理相同。
java.sql.Date
(和
java.util.Date
,它扩展的类)do not,这使得它们非常非常邪恶的类,因为它们是公然的谎言。他们存储自纪元以来经过的毫秒数,并尝试使用一些数学方法将其转换为日期,这意味着时区问题可能会搞砸。地球上几乎每个地方都以这样或那样的方式改变了时区的某些方面(例如在冬令时或夏令时开始时改变日期),这就是为什么依赖时区信息是如此有害的原因:看起来正常工作,直到不能正常工作为止。不容易测试的错误才是真正糟糕的错误。这就是为什么它非常非常重要,您永远不要使用
java.util.Date
及其所有邪恶的后代,例如
java.sql.Date
java.sql.Timestamp

一旦有了

java.time
对象:它们就有
.isEqual
方法,它们的格式化和解析工具是线程安全的,等等。你的问题将会消失。

© www.soinside.com 2019 - 2024. All rights reserved.