Java基础-concurrent (2)

较好的硬件整合
单线程代码在整合底层硬件的时候往往具有更好的优势。首先,当能确定代码只在单线程模式下执行的时候,通常能够创建更优化的数据结构和算法。

合理的作业顺序
基于流水线并发模型实现的并发系统,在某种程度上是有可能保证作业的顺序的。作业的有序性使得它更容易地推出系统在某个特定时间点的状态

缺点

编写难度大
好在有一些平台框架可以直接使用,如Akka,Node.JS等

跟踪困难
流水线并发模型最大的缺点是作业的执行往往分布到多个工作者上,并因此分布到项目中的多个类上。这样导致在追踪某个作业到底被什么代码执行时变得困难。

函数式并行

函数式并行的基本思想是采用函数调用实现程序。函数可以看作是代理人agents或者actor,函数之间可以像流水线模型(反应器或者事件驱动系统)那样互相发送消息。
函数都是通过拷贝来传递参数的,所以除了接收函数外没有实体可以操作数据。这对于避免共享数据的竞态来说是很有必要的。同样也使得函数的执行类似于原子操作。每个函数调用的执行独立于任何其他函数的调用。

Runnable、Callable、Future、Thread、FutureTask

Java并发中主要以Runnable、Callable、Future三个接口作为基础。

Runnable

实例想要被线程执行,可以通过实现Runnable接口。
。通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。

Callable

Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable不会返回结果,并且无法抛出经过检查的异常。

Future

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。
主要方法如下:

cancel(boolean mayInterruptIfRunning)
试图取消对此任务的执行。

get()
如有必要,等待计算完成,然后获取其结果。

get(long timeout, TimeUnit unit)
如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。

isCancelled()
如果在任务正常完成前将其取消,则返回 true。

isDone()
如果任务已完成,则返回 true。

Thread 线程的创建

在Java中,我们有2个方式创建线程:

通过直接继承thread类,然后覆盖run()方法。

构建一个实现Runnable接口的类, 然后创建一个thread类对象并传递Runnable对象作为构造参数

线程的运行流程

我们在主线程中创建5个子线程,每个子线程通过构造函数初始化number的值,来实现1-5内的乘法表:

package com.molyeo.java.concurrent; public class ThreadTest { public static void main(String[] args) { System.out.println("main thread start"); for (int i = 1; i <= 5; i++) { Calculator calculator = new Calculator(i); Thread thread = new Thread(calculator); thread.start(); } System.out.println("main thread end"); } } class Calculator implements Runnable { private int number; public Calculator(int number) { this.number = number; } @Override public void run() { for (int i = 1; i <= 5; i++) { System.out.printf("%s: %d * %d = %d \n", Thread.currentThread().getName(), number, i, i * number); } } }

程序输出如下:

main thread start Thread-0: 1 * 1 = 1 Thread-0: 1 * 2 = 2 Thread-0: 1 * 3 = 3 Thread-0: 1 * 4 = 4 Thread-0: 1 * 5 = 5 Thread-4: 5 * 1 = 5 Thread-4: 5 * 2 = 10 Thread-4: 5 * 3 = 15 Thread-4: 5 * 4 = 20 Thread-4: 5 * 5 = 25 Thread-3: 4 * 1 = 4 Thread-3: 4 * 2 = 8 Thread-2: 3 * 1 = 3 Thread-2: 3 * 2 = 6 Thread-2: 3 * 3 = 9 Thread-2: 3 * 4 = 12 Thread-1: 2 * 1 = 2 Thread-1: 2 * 2 = 4 Thread-1: 2 * 3 = 6 main thread end Thread-1: 2 * 4 = 8 Thread-3: 4 * 3 = 12 Thread-3: 4 * 4 = 16 Thread-3: 4 * 5 = 20 Thread-2: 3 * 5 = 15 Thread-1: 2 * 5 = 10

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppgsp.html