java线程池-异步

  • 时间:
  • 来源:互联网
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43166227/article/details/103176689

进程与线程

进程:一个正在运行的应用程序在操作系统中被称为一个进程,进程包括一个或多个线程。线程是操作系统分配处理器时间的基本单元,在进程中可以有多个线程同时执行代码。进程之间是相互独立的,一个进程无法访问另一个进程的数据(除非用分布式计算方法),一个进程运行的失败也不会影响其他进程的运行,利用进程可以把工作划分为多个独立的区域。
线程:是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。线程主要由CPU寄存器、调用栈和线程本地存储器组成。CPU寄存器主要记录当前执行线程的状态,调用栈主要用于维护所调用内存和数据,存储器则用于存放线程的状态信息。
进程和线程的区别:线程作为调度和分配的基本单位,进程作为资源的基本单位;进程之间可以并发执行,线程也可以;进程是拥有资源的一个独立单元,线程不拥有系统资源,多个线程共享内存单元。

同步与异步

同步:就是运行一段程序时,在没有执行完成并得到结果之前,不会继续执行后续程序。
异步:当异步执行一段程序时,在没有得到结果之前,就可以继续执行后续操作。当异步过程完成之后,通过状态来回通知执行者。对于异步执行过程,执行结果不受调用者控制。通知执行者的方式如下:

  • 状态,即监听执行者的状态(轮询),执行者每隔一定时间检查一次,效率低;
  • 通知,当被执行者执行完成后,发出通知告知调用者;
  • 回调,与通知类似,当异步操作执行完成之后,会调用执行者提供的回调函数。

同步和异步的区别:最明显的区别,在于是否需要等待上一段程序的执行结果,才能继续执行接下来的程序。

线程池

基本思想是建立对象池的思想,开辟一块内存空间,里面存放多个线程,池中线程调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象回到池中。线程池主要用来解决线程生命周期开销问题和资源不足问题。
线程池基本组成:线程池管理器、工作线程、任务队列、任务接口等部分。

  • 线程池管理器:创建、销毁并管理线程池,将工作线程放入线程池中;
  • 工作线程:可以循环执行任务的线程,在没有任务时等待;
  • 任务队列:提供缓冲机制,将没有处理的任务放在任务队列中;
  • 任务接口:用于规定任务的入口、任务执行完成后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行。

线程池基本功能:创建线程池,销毁线程池,添加任务。

线程池的作用

  • 重用存在的线程,减少对象创建、消亡的开销,性能佳;
  • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞;
  • 提供定时执行、定期执行、单线程、并发数控制等功能;
  • 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存。

异步调用

创建线程
(1)继承Thread类,扩展线程

class DemoThread extends Thread {

    @Override
    public void run() {
        super.run();
        // Perform time-consuming operation...
    }
}
DemoThread t = new DemoThread();
t.start();
//继承Thread类,覆盖run()方法。
//创建线程对象并用start()方法启动线程。

(2)实现Runnable接口

public class DemoActivity extends BaseActivity implements Runnable {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Thread t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {

    }
}
//如果你要继承其他类,调用Runnable接口

(3)扩展
FutureTask 实现了 Runnable 和 Future,所以兼顾两者优点,既可以在 Thread 中使用,又可以在 ExecutorService 中使用。

Callable<String> callable = new Callable<String>() {
    @Override
    public String call() throws Exception {
        return "测试";
    }
};
FutureTask<String> task = new FutureTask<String>(callable);
Thread t = new Thread(task);
t.start(); // 启动线程
task.cancel(true); // 取消线程
//Callable 的 call() 方法可以返回值和抛出异常,而 Runnable 的 run() 方法没有这些功能
//使用 FutureTask 的好处是 FutureTask 是为了弥补 Thread 的不足而设计的,它可以让程序员准确地知道线程什么时候执行完成并获得到线程执行完成后返回的结果。FutureTask 是一种可以取消的异步的计算任务,它的计算是通过 Callable 实现的,它等价于可以携带结果的 Runnable,并且有三个状态:等待、运行和完成。

线程池
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

  • newSingleThreadExecutor:单线程的线程池,如果这个唯一的线程因为异常结束,那么会有一个新的线程替代它。
//创建一个单线程化的线程池,用一个唯一的线程来执行任务,保证所有任务按照指定顺序执行
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
  for (int i = 0; i < 10; i++) {
   final int index = i;
   singleThreadExecutor.execute(new Runnable() {
    public void run() {
     try {
      System.out.println(index);
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
  }
 }
}
  • newFixedThreadPool:创建固定大小的线程池,每次提交一个任务创建一个线程,直到达到指定线程池的到。线程池的大小一旦达到最大值就保持不变,如果某个线程异常崩掉,会创建一个新的线程来替代它。
//创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
  for (int i = 0; i < 10; i++) {
   final int index = i;
   fixedThreadPool.execute(new Runnable() {
    public void run() {
     try {
      System.out.println(index);
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
  }
 }
}
  • newCachedThreadPool:创建一个可缓存的线程池,线程池的大小超过处理任务所需要的线程,那么回收多余的线程。
//创建一个可缓存线程池,线程池大小超过处理需要,可灵活回收空闲线程,若任务增加,则新建线程。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
   final int index = i;
   try {
    Thread.sleep(index * 1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   cachedThreadPool.execute(new Runnable() {
    public void run() {
     System.out.println(index);
    }
   });
  }
 }
}
  • newScheduledThreadPool:创建一个大小无限的线程池,此线程池可以定时以及周期性执行任务的需求。
//创建一个定长线程池,支持定时和周期性执行任务。
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
  scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
   public void run() {
    System.out.println("delay 1 seconds, and excute every 3 seconds");
   }
  }, 1, 3, TimeUnit.SECONDS);
 }
}

备注
execute(Runnable x) 没有返回值。可以执行任务,但无法判断任务是否成功完成。实现Runnable接口;submit(Runnable x) 返回一个future。可以用这个future来判断任务是否成功完成。实现Callable接口。

线程超时
在java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。 Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实现,可以来进行异步计算。

//Executor方式
ExecutorService executor = Executors.newSingleThreadExecutor();    
FutureTask<String> future =    
       new FutureTask<String>(new Callable<String>() {//使用Callable接口作为构造参数    
         public String call() {    
           //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型    
       }});    
executor.execute(future);    
//在这里可以做别的任何事情    
try {    
    result = future.get(5000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果    
} catch (InterruptedException e) {    
    futureTask.cancel(true);    
} catch (ExecutionException e) {    
    futureTask.cancel(true);    
} catch (TimeoutException e) {    
    futureTask.cancel(true);    
} finally {    
    executor.shutdown();    
}    

//submit方式
ExecutorService executor = Executors.newSingleThreadExecutor();    
FutureTask<String> future = executor.submit(    
   new Callable<String>() {//使用Callable接口作为构造参数    
       public String call() {    
      //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型    
   }});    
try {    
    result = future.get(5000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果    
} catch (InterruptedException e) {    
    futureTask.cancel(true);    
} catch (ExecutionException e) {    
    futureTask.cancel(true);    
} catch (TimeoutException e) {    
    futureTask.cancel(true);    
} finally {    
    executor.shutdown();    
}    

参考

https://www.cnblogs.com/mhq-martin/p/9035640.html
https://mp.weixin.qq.com/ssrc=11&timestamp=1574326462&ver=1987&signature=hA0yXRVZYqa0D13D8q4npz6UQx3ed87SzSxk0WHRleFM31ZZNTPeQCOVvpNVwYFHhSudYoKOsldjOTL5GEwRwLBac2wksWql*c0nij3VAoiLGWygXCn5g1tbEFLQY1&new=1
https://blog.csdn.net/a1015088819/article/details/53099943

本文链接http://element-ui.cn/news/show-67.aspx