【问题标题】:Thread with Lambda expression带有 Lambda 表达式的线程
【发布时间】:2015-07-14 20:35:49
【问题描述】:

我在第 42 和 43 行有一个错误:Thread t1=new Thread(()->prod.test());Thread t2=new Thread(()->cons.test()); 未处理的异常类型 InterruptedException。如果我尝试快速修复,它会创建带有 catch Exception 的 try catch,它会出现相同的错误,并会尝试以相同的方式修复它,继续用 try catch 包围它。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

interface Predicate {
    public void test() throws InterruptedException;
}

class MyClass {
    int num = 0;
    Lock lock = new ReentrantLock();

    public void produce() throws InterruptedException {
        lock.lock();
        for (int i = 0; i < 1000; i++) {
            num++;
            Thread.sleep(1);
        }
        lock.unlock();
    }

    public void consume() throws InterruptedException {
        lock.lock();
        for (int i = 0; i < 1000; i++) {
            num--;
            Thread.sleep(1);
        }
        lock.unlock();
    }

    public int getNum() {
        return num;
    }

}

public class Main00 {

    public static void main(String[] args) throws InterruptedException {
        MyClass c = new MyClass();
        Predicate prod = c::produce;
        Predicate cons = c::consume;
        Thread t1 = new Thread(() -> prod.test());
        Thread t2 = new Thread(() -> cons.test());
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        long end = System.currentTimeMillis();
        System.out.println("time taken " + (end - start) + " num = "
                + c.getNum());
    }

}

【问题讨论】:

    标签: java multithreading lambda interrupted-exception


    【解决方案1】:

    您已经创建了一个函数式接口Predicate,其方法被声明为抛出一个InterruptedException,这是一个检查异常。但是,您在 lambda 表达式的主体中调用 test() 作为 the Thread constructor that takes a Runnable 的参数,其 run() method is not declared to throw any checked exceptions。因此,因为异常没有在body中被捕获,所以出现编译器错误。

    顺便说一句,将您自己的接口命名为 Predicate 可能会造成混淆,因为 built-in functional interface java.util.function.Predicate 的函数方法返回 boolean

    因为run()不能抛出Exception,你必须catch这个异常并处理它。您可能会记录异常及其堆栈跟踪。您可以将异常包装在RuntimeException 中。无论哪种方式,捕获检查的异常都将允许代码编译。示例:

    Thread t1 = new Thread(() -> {
        try {
            prod.test();
        } catch (InterruptedException e) {
            // handle: log or throw in a wrapped RuntimeException
            throw new RuntimeException("InterruptedException caught in lambda", e);
        }
    });
    

    【讨论】:

    • Exception 'java.lang.InterruptedException' 不会在相应的 try 块中抛出。
    • @ShadowGames Predicate 的这个特殊定义声明 test 会抛出 InterruptedException,所以它可以被抛出并且必须被捕获。
    【解决方案2】:

    如果您打算只运行一个不带参数的方法,您可以将 lambda 替换为方法引用。

    例如:

    Thread t = new Thread(() -> {
            foo();
        });
    

    可以更简洁地表达为

    Thread t = new Thread(this::foo);
    

    【讨论】:

    • 我假设您仍然需要致电 t.start()(这与问题无关,但在我了解 lambdas 之前,最好问一下!)。
    【解决方案3】:

    正如@rgettman 所说,Predicate 这个名字令人不快……无论如何,您可以利用 Java 中的 default 方法:

    interface PredicateButPleaseChangeMyName {
    
        void test() throws InterruptedException;
    
        default void tryTest() {
           try {
              this.test();
           } catch (InterruptedException e) {
              // handle e (log or wrap in a RuntimeException)
           }
        }
    }
    

    然后,在您的 main 方法中,只需通过调用默认的 tryTest() 方法来创建线程:

    Thread t1 = new Thread(() -> prod.tryTest());
    Thread t2 = new Thread(() -> cons.tryTest());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-02
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多