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

vin*_*001 -2 java timestamp date callable synchronized

我使用 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) {...}
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)
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;
    }
Run Code Online (Sandbox Code Playgroud)
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;
    }
}
Run Code Online (Sandbox Code Playgroud)

rzw*_*oot 5

JDBC 的 API 是半损坏的,因为它保证基于 的getTimestamp/以及基于 的/的存在。不幸的是,这两种类型都会扩展;所有这些类型都被破坏了。setTimestampjava.sql.TimestampsetDategetDatejava.sql.Datejava.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
}
Run Code Online (Sandbox Code Playgroud)

LocalDate 和 OffsetDateTime 都保证可以工作。LocalDateTime 和 ZonedDateTime 取决于您的 JDBC 实现。例如,Postgres JDBC 驱动程序支持LocalDateLocalTimeLocalDateTimeOffsetDateTime。分别是 、DATETIME WITHOUT TIME ZONETIMESTAMP WITHOUT TIME ZONE的Java 等效项TIMESTAMP WITH TIME ZONE。和TIME不带时区TIMESTAMP变体的别名。

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

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

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