进程是系统中正在运行的一个程序,程序一旦运行就是进程。
进程可以看成程序执行的一个实例。进程是系统资源分配的独立实体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构,如果想让一个进程访问另一个进程的资源,需要使用进程间通信,比如管道,文件,套接字等。
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
Thread类构造方法:
1.Thread();
2.Thread(String name);
3.Thread(Runable r);
4.Thread(Runable r, String name);
public class ExtendThread extends Thread {
@Override
public void run() {
System.out.println("继承Thread类实现线程.......Name:"+this.getName()+" Id:"+this.getId());
}
public static void main(String[] args) {
Thread thread = new ExtendThread();
thread.start();
}
}
Thread 类常用方法
start();//启动线程
getId();//获得线程ID
getName();//获得线程名字
getPriority();//获得优先权
isAlive();//判断线程是否活动
isDaemon();//判断是否守护线程
getState();//获得线程状态
sleep(long mill);//休眠线程
join();//等待线程结束
yield();//放弃cpu使用权利
interrupt();//中断线程
currentThread();//获得正在执行的线程对象
public class ImpRunnable implements Runnable {
@Override
public void run() {
System.out.println("继承Runnable接口实现线程...");
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
}
}
public static void main(String[] args) {
Runnable runnable = new ImpRunnable();
Thread thread = new Thread(runnable);
thread.start();
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
}
}
}
Callable接口是一个泛型接口,也声明为了“函数式接口”。其唯一的抽象方法call有返回值,返回值的类型为泛型形参的实际类型。call抽象方法还有一个Exception的异常声明,容许方法内部的异常不经过捕获。
@FunctionalInterface
public interface Callable {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Callable接口与Runnable接口相比,还有一个很大的不同:Callable接口的实例不能作为Thread线程实例的target来使用;而Runnable接口实例可以作为Thread线程实例的target构造参数,开启一个Thread线程。由此引出在Callable实例和Thread 的target成员之间的一个搭桥的类——FutureTask类
FutureTask类代表一个未来执行的任务,表示新线程所执行的操作。FutureTask类也位于java.util.concurrent包中。FutureTask类的构造函数的参数为Callable类型,实际上是对Callable类型的二次封装,可以执行Callable的call方法。FutureTask类间接地继承了Runnable接口,从而可以作为Thread实例的target执行目标。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
FutureTask内部有一个run方法。这个run方法是Runnable接口的抽象方法,在FutureTask类的内部提供了自己的实现。在Thread线程实例执行时,会将这个run方法作为target目标去异步执行。在FutureTask内部的run实现代码中,会执行其callable成员的call方法。执行完成后,将结果保存起来。FutureTask内部有另一个重要的成员——outcome属性,用于保存结果:outcome属性所保存的结果,可供FutureTask类的结果获取方法(如get)来获取。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class CallThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("继承Callable接口实现线程...");
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
}
return 1000;
}
public static void main(String[] args) throws Exception{
Callable<Integer> callable = new CallThread();
FutureTask<Integer> ft =new FutureTask<>(callable);
Thread thread = new Thread(ft);
thread.start();
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"循环输出:"+i);
}
Integer integer = ft.get();//注意i此方法会阻塞当前线程直到获取到返回结果
System.out.println("Callable 接口返回值"+integer);
}
}
Guava 是谷歌公司提供的Java扩展包,提供了一种异步回调的解决方案,包中的很多类,都是对java.util.concurrent能力的扩展和增强。例如,Guava的异步任务接口ListenableFuture,扩展了Java的Future接口,实现了非阻塞获取异步结果的功能。
(1)引入了一个新的接口ListenableFuture,继承了Java的Future接口,使得Java的Future异步任务,在Guava中能被监控和获得非阻塞异步执行的结果。
(2)引入了一个新的接口FutureCallback,这是一个独立的新接口。该接口的目的,是在异步任务执行完成后,根据异步结果,完成不同的回调处理,并且可以处理异步结果。
FutureCallback是一个新增的接口,用来填写异步任务执行完后的监听逻辑。FutureCallback拥有两个回调方法:(1)onSuccess方法,在异步任务执行成功后被回调;调用时,异步任务的执行结果,作为onSuccess方法的参数被传入。
(2)onFailure方法,在异步任务执行过程中,抛出异常时被回调;调用时,异步任务所抛出的异常,作为onFailure方法的参数被传入。
@GwtCompatible
public interface FutureCallback<V> {
void onSuccess(@Nullable V var1);
void onFailure(Throwable var1);
}
Guava的FutureCallback与Java的Callable的区别:
(1)Java的Callable接口,代表的是异步执行的逻辑。
(2)Guava的FutureCallback接口,代表的是Callable异步逻辑执行完成之后,根据成功或者异常两种情况,所需要执行的善后工作。
Guava的ListenableFuture接口是对Java的Future接口的扩展.
ListenableFuture仅仅增加了一个方法——addListener方法。它的作用就是将前一小节的FutureCallback善后回调工作,封装成一个内部的Runnable异步回调任务,在Callable异步任务完成后,回调FutureCallback进行善后处理。
在实际编程中,可以使用Guava的Futures工具类,它有一个addCallback静态方法,可以将FutureCallback的回调实例绑定到ListenableFuture异步任务。
第1步:实现Java的Callable接口,创建异步执行逻辑。还有一种情况,如果不需要返回值,异步执行逻辑也可以实现Java的Runnable接口。
第2步:创建Guava线程池。
第3步:将第1步创建的Callable/Runnable异步执行逻辑的实例,通过submit提交到Guava线程池,从而获取ListenableFuture异步任务实例。
第4步:创建FutureCallback回调实例,通过Futures.addCallback将回调实例绑定到ListenableFuture异步任务上。完成以上四步,当Callable/Runnable异步执行逻辑完成后,就会回调异步回调实例FutureCallback的回调方法onSuccess/onFailure。
泡茶案例
import com.crazymakercircle.util.Logger;
import com.google.common.util.concurrent.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by 尼恩 at 疯狂创客圈
*/
public class GuavaFutureDemo {
public static final int SLEEP_GAP = 500;
public static String getCurThreadName() {
return Thread.currentThread().getName();
}
static class HotWarterJob implements Callable<Boolean> //①
{
@Override
public Boolean call() throws Exception //②
{
try {
Logger.info("洗好水壶");
Logger.info("灌上凉水");
Logger.info("放在火上");
//线程睡眠一段时间,代表烧水中
Thread.sleep(SLEEP_GAP);
Logger.info("水开了");
} catch (InterruptedException e) {
Logger.info(" 发生异常被中断.");
return false;
}
Logger.info(" 烧水工作,运行结束.");
return true;
}
}
static class WashJob implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
try {
Logger.info("洗茶壶");
Logger.info("洗茶杯");
Logger.info("拿茶叶");
//线程睡眠一段时间,代表清洗中
Thread.sleep(SLEEP_GAP);
Logger.info("洗完了");
} catch (InterruptedException e) {
Logger.info(" 清洗工作 发生异常被中断.");
return false;
}
Logger.info(" 清洗工作 运行结束.");
return true;
}
}
//泡茶线程
static class MainJob implements Runnable {
boolean warterOk = false;
boolean cupOk = false;
int gap = SLEEP_GAP / 10;
@Override
public void run() {
while (true) {
try {
Thread.sleep(gap);
Logger.info("读书中......");
} catch (InterruptedException e) {
Logger.info(getCurThreadName() + "发生异常被中断.");
}
if (warterOk && cupOk) {
drinkTea(warterOk, cupOk);
}
}
}
public void drinkTea(Boolean wOk, Boolean cOK) {
if (wOk && cOK) {
Logger.info("泡茶喝,茶喝完");
this.warterOk = false;
this.gap = SLEEP_GAP * 100;
} else if (!wOk) {
Logger.info("烧水失败,没有茶喝了");
} else if (!cOK) {
Logger.info("杯子洗不了,没有茶喝了");
}
}
}
public static void main(String args[]) {
//新起一个线程,作为泡茶主线程
MainJob mainJob = new MainJob();
Thread mainThread = new Thread(mainJob);
mainThread.setName("主线程");
mainThread.start();
//烧水的业务逻辑
Callable<Boolean> hotJob = new HotWarterJob();
//清洗的业务逻辑
Callable<Boolean> washJob = new WashJob();
//创建java 线程池
ExecutorService jPool =
Executors.newFixedThreadPool(10);
//包装java线程池,构造guava 线程池
ListeningExecutorService gPool =
MoreExecutors.listeningDecorator(jPool);
//提交烧水的业务逻辑,取到异步任务
ListenableFuture<Boolean> hotFuture = gPool.submit(hotJob);
//绑定任务执行完成后的回调,到异步任务
Futures.addCallback(hotFuture, new FutureCallback<Boolean>() {
public void onSuccess(Boolean r) {
if (r) {
mainJob.warterOk = true;
}
}
public void onFailure(Throwable t) {
Logger.info("烧水失败,没有茶喝了");
}
});
//提交清洗的业务逻辑,取到异步任务
ListenableFuture<Boolean> washFuture = gPool.submit(washJob);
//绑定任务执行完成后的回调,到异步任务
Futures.addCallback(washFuture, new FutureCallback<Boolean>() {
public void onSuccess(Boolean r) {
if (r) {
mainJob.cupOk = true;
}
}
public void onFailure(Throwable t) {
Logger.info("杯子洗不了,没有茶喝了");
}
});
}
}
//绑定任务执行完成后的回调,到异步任务
Futures.addCallback(washFuture, new FutureCallback<Boolean>() {
public void onSuccess(Boolean r) {
if (r) {
mainJob.cupOk = true;
}
}
public void onFailure(Throwable t) {
Logger.info("杯子洗不了,没有茶喝了");
}
});
}
}