📜  Java和 Android 多线程编程中的 Runnable、Callable、Future、Executor

📅  最后修改于: 2022-05-13 01:54:40.693000             🧑  作者: Mango

Java和 Android 多线程编程中的 Runnable、Callable、Future、Executor

多线程是一种Java功能,它允许同时执行程序的两个或多个部分,以最大限度地利用 CPU。这样一个程序的每个部分都称为一个线程。因此,线程是进程中的轻量级进程。

可运行

任何其实例打算由线程执行的类都应实现 Runnable 接口。该类必须定义一个不带参数的运行方法。此接口旨在为希望在活动时运行代码的对象提供标准协议。例如,Thread 实现了 Runnable 接口。处于活动状态仅仅意味着线程已经开始并且尚未终止。此外,Runnable 允许一个类在不继承 Thread 的情况下处于活动状态。实现 Runnable 的类可以通过创建 Thread 实例并将自身作为目标传递而无需子类化 Thread 即可执行代码。

要使用 Runnable 创建新线程,请执行以下步骤:

  1. 创建一个 Runnable 实现者并调用 run() 方法。
  2. 创建一个 Thread 实例并将实现者传递给它。 Thread 有一个接受 Runnable 实例的函数Object() { [native code] }。
  3. 在 Thread 实例上调用 start(); start 在内部调用实现者的 run()。调用 start() 会生成一个执行 run() 中指定的代码的新线程。
Java
public class Comment implements Activity {
    private Date GeeksCreatedAt;
    public Comment(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
    @Override public Date getCoursesAddedAt()
    {
        return GeeksCreatedAt;
    }
    @Override public String toString()
    {
        return "Comment{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}
public class GfG implements Activity {
  
    private Date GeeksCreatedAt;
  
    public GfG(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCoursesAddedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "GfG{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}


Java
public class Like implements Activity {
    private Date GeeksCreatedAt;
  
    public Like(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "Like{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}


Java
public class Post implements Activity {
    private Date GeeksCreatedAt;
    public Post(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "Post{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}


Java
public class RemoteService {
    private static int cores
        = Runtime.getRuntime().availableProcessors();
    private static ExecutorService executor
        = Executors.newFixedThreadPool(cores + 1);
    public void stop() { executor.shutdown(); }
    public void
    getUserRecentGfgActs(ResultCallback callback)
    {
        executor.execute(() -> {
            List gfgLikes = new ArrayList<>();
            List gfgPOsts = new ArrayList<>();
            List comments = new ArrayList<>();
            List gfgCourses = new ArrayList<>();
            Future > futureGfgLikes
                = executor.submit(getGfgLikes(
                    "https://geeksforgeeks.org.com/gfgLikes"));
            Future > futureComments
                = executor.submit(getComments(
                    "https://geeksforgeeks.org.com/comments"));
            Future > futureGfgPOsts
                = executor.submit(getGfgPOsts(
                    "https://geeksforgeeks.org.com/gfgPOsts"));
            Future > futureGfgCourses
                = executor.submit(getGfgCourses(
                    "https://geeksforgeeks.org.com/gfgCourses"));
  
            try {
                gfgLikes = futureGfgLikes.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                gfgPOsts = futureGfgPOsts.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                comments = futureComments.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                gfgCourses = futureGfgCourses.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            List gfgActs = new ArrayList<>();
            gfgActs.addAll(gfgLikes);
            gfgActs.addAll(gfgPOsts);
            gfgActs.addAll(comments);
            gfgActs.addAll(gfgCourses);
  
            Collections.sort(
                gfgActs,
                (activity1, activity2)
                    -> activity1.getCreatedAt().compareTo(
                        activity2.getCreatedAt()));
  
            callback.onResult(gfgActs);
        });
    }
  
    private Callable > getGfgLikes(String url)
    {
        return () ->
        {
            System.out.println("getGfgLikes");
            Thread.sleep(200);
            return Arrays.asList(
                new Like(new Date(1534334348560L)),
                new Like(new Date(1554365436546960L)));
        };
    }
  
    private Callable > getGfgPOsts(String url)
    {
        return () ->
        {
            System.out.println("getGfgPOsts");
            Thread.sleep(500);
            return Arrays.asList(
                new Post(new Date(15334343448560L)),
                new Post(new Date(153343434460L)));
        };
    }
  
    private Callable > getComments(String url)
    {
        return () ->
        {
            System.out.println("getComments");
            Thread.sleep(200);
            return Arrays.asList(
                new Comment(new Date(15356565648560L)),
                new Comment(new Date(151454545456460L)));
        };
    }
  
    private Callable >
    getGfgCourses(String url)
    {
        return () ->
        {
            System.out.println("getGfgCourses");
            Thread.sleep(6500);
            return Arrays.asList(
                new Friend(new Date(1534543354248560L)),
                new Friend(new Date(15334343546460L)));
        };
    }
}


可调用

产生结果并有能力抛出异常的任务。实现者定义了一个名为 call 的方法,它不接受任何参数。 Callable 接口与 Runnable 接口相似,两者都适用于其实例可能由另一个线程执行的类。另一方面,Runnable 不返回值,也不能抛出检查异常。 Executors 包含用于从其他常见形式转换为 Callable 类的实用方法。为了实现 Runnable,必须实现 run() 方法,该方法不返回任何内容,而为了实现 Callable,必须实现 call() 方法,该方法在完成时返回结果。需要注意的是,不能使用 Callable 创建线程;只有 Runnable 可以这样做。另一个区别是 call() 方法可以抛出异常,而 run() 方法不能。

Java

public class Like implements Activity {
    private Date GeeksCreatedAt;
  
    public Like(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "Like{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}

Java

public class Post implements Activity {
    private Date GeeksCreatedAt;
    public Post(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "Post{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}

未来

Future 是异步计算的结果。提供了确定计算是否完成、等待其完成以及检索计算结果的方法。计算完成后,只能使用 get 方法检索结果,必要时阻塞,直到它准备好。 cancel 方法用于取消事务。提供了额外的方法来确定任务是否正常完成。一旦计算完成,就不能取消。如果您想将 Future 用于可取消性但不提供可用结果,您可以声明 Future?类型并返回 null 作为底层任务的结果。因为它实现了 Future 接口,所以在线程启动后与线程的所有交互都由 FutureTask 对象处理。因此,无需保存 Thread 对象。 FutureTask 对象可用于取消任务、检查任务是否完成或尝试检索结果。

Java

public class RemoteService {
    private static int cores
        = Runtime.getRuntime().availableProcessors();
    private static ExecutorService executor
        = Executors.newFixedThreadPool(cores + 1);
    public void stop() { executor.shutdown(); }
    public void
    getUserRecentGfgActs(ResultCallback callback)
    {
        executor.execute(() -> {
            List gfgLikes = new ArrayList<>();
            List gfgPOsts = new ArrayList<>();
            List comments = new ArrayList<>();
            List gfgCourses = new ArrayList<>();
            Future > futureGfgLikes
                = executor.submit(getGfgLikes(
                    "https://geeksforgeeks.org.com/gfgLikes"));
            Future > futureComments
                = executor.submit(getComments(
                    "https://geeksforgeeks.org.com/comments"));
            Future > futureGfgPOsts
                = executor.submit(getGfgPOsts(
                    "https://geeksforgeeks.org.com/gfgPOsts"));
            Future > futureGfgCourses
                = executor.submit(getGfgCourses(
                    "https://geeksforgeeks.org.com/gfgCourses"));
  
            try {
                gfgLikes = futureGfgLikes.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                gfgPOsts = futureGfgPOsts.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                comments = futureComments.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                gfgCourses = futureGfgCourses.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            List gfgActs = new ArrayList<>();
            gfgActs.addAll(gfgLikes);
            gfgActs.addAll(gfgPOsts);
            gfgActs.addAll(comments);
            gfgActs.addAll(gfgCourses);
  
            Collections.sort(
                gfgActs,
                (activity1, activity2)
                    -> activity1.getCreatedAt().compareTo(
                        activity2.getCreatedAt()));
  
            callback.onResult(gfgActs);
        });
    }
  
    private Callable > getGfgLikes(String url)
    {
        return () ->
        {
            System.out.println("getGfgLikes");
            Thread.sleep(200);
            return Arrays.asList(
                new Like(new Date(1534334348560L)),
                new Like(new Date(1554365436546960L)));
        };
    }
  
    private Callable > getGfgPOsts(String url)
    {
        return () ->
        {
            System.out.println("getGfgPOsts");
            Thread.sleep(500);
            return Arrays.asList(
                new Post(new Date(15334343448560L)),
                new Post(new Date(153343434460L)));
        };
    }
  
    private Callable > getComments(String url)
    {
        return () ->
        {
            System.out.println("getComments");
            Thread.sleep(200);
            return Arrays.asList(
                new Comment(new Date(15356565648560L)),
                new Comment(new Date(151454545456460L)));
        };
    }
  
    private Callable >
    getGfgCourses(String url)
    {
        return () ->
        {
            System.out.println("getGfgCourses");
            Thread.sleep(6500);
            return Arrays.asList(
                new Friend(new Date(1534543354248560L)),
                new Friend(new Date(15334343546460L)));
        };
    }
}

执行人

执行已提交的 Runnable 任务的对象。该接口允许您将任务提交与每个任务将如何执行的机制(例如线程使用、调度等)分离。通常使用 Executor 代替显式创建线程。例如,而不是调用 new Thread(new(RunnableTask()))。 start() 用于序列中的每个任务。顾名思义,它是一个具有固定数量线程的线程池。提交给 executor 的任务由 n 个线程执行,任何额外的任务都存储在 LinkedBlockingQueue 中。它采用阻塞队列。

创建并运行一个简单的执行器,我们将在其中创建一个任务并在固定池中运行它。

  1. Task 类实现 Callable 并具有 String 参数。还说会抛出异常。
  2. 要执行“Task”类中的任务,我们必须首先实例化 Task 类并将其传递给 executor 执行。
  3. Future 对象的结果应该被打印和显示。