java - 如何在 java 中创建自定义编译器警告?

标签 java concurrency semaphore compiler-warnings

我正在寻找类似于实现 java.lang.AutoCloseable 接口(interface)的东西,其中会生成一个编译器警告,指示资源泄漏:'xxxx'从未关闭

其用例是 java 中同步集合的包装器。包装器有一个内部信号量来防止集合的并发修改。

它允许对集合进行原子操作,在这种情况下,信号量在内部获取和释放。它还允许从外部获取锁,从而提供可以在集合上执行操作的唯一 key 。 key 必须在“交易”结束时释放。

我的目标是在同一方法中获取锁但未释放锁时创建编译器警告,以防止死锁。防止这种情况发生的替代设计解决方案也是可以接受的。

这是一个有趣的小问题,所以我很感激任何对此的深入了解。

最佳答案

正如你所说

An alternative design solution that would prevent this is also acceptable.

所以这就是:作为替代设计解决方案,使用函数式编程

与其找出错误,为什么不从一开始就阻止错误的发生呢?

由于缺乏您的源代码,我对您的代码做了一些假设:

  • Semaphore是您的类(或接口(interface)),为您的 SynchronizedCollection 提供信号量.
  • Semaphore提供了两种方法obtain()release() .

您实际上面临的问题是国家的问题。 状态变化导致时间耦合obtain()release() 必须按顺序调用。您可以使用函数式编程中的元素作为替代设计。

Semaphore目前看起来像这样:

public class Sempahore {
    // ...
    public void obtain() {
        // Lock code
    }
    public void release() {
        // Release code
    }
}

Semaphore用户当前看起来像这样:

semaphore.obtain();
// Code protected by the Sempahore.
semaphore.release();

解决方案是结合obtain()release()到一个函数中,该函数将要保护的代码作为其参数。这种技术也称为“传递 block ”,或更正式地称为“高阶函数”,即采用另一个函数作为参数或返回另一个函数的函数。

Java 也有函数指针,不是直接的,而是通过接口(interface)引用间接的。从 Java 8 开始,只有一个抽象方法的接口(interface)甚至被称为函数式接口(interface),并且 Java 8 提供了可选注释 @FunctionalInterface为此。

所以,你的class Sempahore可以看起来像这样:

public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V> void protect(final Callable<V> c) throws Exception {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}

在 Java 7 及更早版本中,调用者看起来像这样:

semaphore.protect(new Callable<Object>() {
    public Object call() {
        // Code protected by the Semaphore.
    }
});

在 Java 8 及更高版本中,代码也可能如下所示:

semaphore.protect(() -> {
    // Code protected by the Semaphore.
});

此解决方案的怪癖

Java 有一个方面在这种情况下完全糟糕:异常处理。对于函数式编程,迫切需要解决这个问题,但 Oracle 没有。我仍然希望 Java 9,但这对所有像 java.util.stream 这样损坏的 API 没有帮助。那已经在野外了。 Java 8 仍然保留检查异常的处理或声明规则,但函数式编程并没有很好地考虑到这一点。

有一些解决方法:

  • 使用Runnable ,如果不需要返回值。
  • 使用您自己的Callable为异常声明类型参数的接口(interface)。

我打赌使用Runnable很简单且不言自明,因此我不会详细说明。

使用您自己的 Callable 版本界面如下所示:

public interface ProtectedCode<V,E> {
    V call() throws E;
}

public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V, E> void protect(final ProtectedCode<V, E> c) throws E {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}

现在你不需要搞乱 Exception,只要类型参数 E 的类型推断有限(因为它只能反射(reflect)一种类型,而不是类型集)。在编译器中产生合理的结果。

如果您想对用户格外友好,您实际上可以提供 protect 的三种变体。方法:

  • public void protect(final Runnable r)
  • public <V> V protect(final Callable<V> c) throws Exception
  • public <V,E> V protect(final ProtectedCode<V,E> c) throws E

关于java - 如何在 java 中创建自定义编译器警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28949464/

相关文章:

java - 使用 executeupdate 从 mysql 数据库中删除记录(netbeans)

java - 例如,调用 notifyAll 的顺序如何影响 Java 中的执行?

java - Java并发更新oracle表

java - 使用监视器概念实现信号量

java - 选择实体中包含的列表的子集

java - 如何忽略 Flyway 的占位符表达式?

java - 使用本地对象引用的堆栈限制

sql-server - SQL Server 代理 - 信号量超时

c - 在 C 中未正确创建信号量

java - JDBC executeQuery 无故显示错误