线程池本质的概念就是一堆线程一起完成一件事情。

Executor

  1. package java.util.concurrent;
  2. public interface Executor {
  3. void execute(Runnable command);
  4. }

ExecutorService

  1. package java.util.concurrent;
  2. public interface ExecutorService extends Executor

ScheduledExecutorService

  1. package java.util.concurrent;
  2. public interface ScheduledExecutorService extends ExecutorService

Executors

  1. package java.util.concurrent;
  2. public class Executors

线程池分类

  创建线程池使用类:java.util.concurrent.Executors

  • 创建无大小限制的线程池

    1. public static ExecutorService newCachedThreadPool() {
    2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
    3. 60L, TimeUnit.SECONDS,
    4. new SynchronousQueue<Runnable>());
    5. }
  • 创建固定大小的线程池
    1. public static ExecutorService newFixedThreadPool(int nThreads) {
    2. return new ThreadPoolExecutor(nThreads, nThreads,
    3. 0L, TimeUnit.MILLISECONDS,
    4. new LinkedBlockingQueue<Runnable>());
    5. }
  • 创建单线程池
    1. public static ExecutorService newSingleThreadExecutor() {
    2. return new FinalizableDelegatedExecutorService
    3. (new ThreadPoolExecutor(1, 1,
    4. 0L, TimeUnit.MILLISECONDS,
    5. new LinkedBlockingQueue<Runnable>()));
    6. }
  • 创建定时调度池
    1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    2. return new ScheduledThreadPoolExecutor(corePoolSize);
    3. }

创建四种线程池

当Executors创建完成了线程池之后可以返回“ExecutorService”接口对象,而这个对象里面有两个方法来接收线程的执行:

接收Callable:

  1. public <T> Future<T> submit(Callable<T> task);

接收Runnable:

  1. public Future<?> submit(Runnable task);

  

范例:创建无限量线程池

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4.  
  5. public class ExecutorDemo {
  6. public static void main(String[] args) {
  7. ExecutorService service = Executors.newCachedThreadPool(); //创建一个线程池
  8. for (int i = 0; i < 5; i++) {
  9. service.submit(new Runnable() {
  10. @Override
  11. public void run() {
  12. System.out.println(Thread.currentThread().getName()+"执行操作");
  13. }
  14. });
  15. }
  16. service.shutdown(); //线程池执行完毕后需要关闭
  17. }
  18. }

  无限量大小的线程池会根据内部线程的执行状况来进行线程对象个数的控制。

范例:创建有限量的线程池

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4.  
  5. public class ExecutorDemo {
  6. public static void main(String[] args) {
  7. ExecutorService service = Executors.newFixedThreadPool(3); //创建一个线程池
  8. for (int i = 0; i < 5; i++) {
  9. service.submit(new Runnable() {
  10. @Override
  11. public void run() {
  12. System.out.println(Thread.currentThread().getName()+"执行操作");
  13. }
  14. });
  15. }
  16. service.shutdown(); //线程池执行完毕后需要关闭
  17. }
  18. }

范例:创建单线程池

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4.  
  5. public class ExecutorDemo {
  6. public static void main(String[] args) {
  7. ExecutorService service = Executors.newSingleThreadExecutor(); //创建一个线程池
  8. for (int i = 0; i < 5; i++) {
  9. service.submit(new Runnable() { //线程池会负责启动
  10. @Override
  11. public void run() {
  12. System.out.println(Thread.currentThread().getName()+"执行操作");
  13. }
  14. });
  15. }
  16. service.shutdown(); //线程池执行完毕后需要关闭
  17. }
  18. }

除了以上的三种线程池之外还可以创建一个定时调度池,这个调度池主要是以时间间隔调度为主。如果要创建调度池则使用ScheduledExecutorService接口完成,该接口之中包含有如下的两个方法:

  • 延迟启动

    1. public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);
  • 间隔调度
    1. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);

范例:创建调度池

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.Executors;
  3. import java.util.concurrent.ScheduledExecutorService;
  4. import java.util.concurrent.TimeUnit;
  5.  
  6. public class ExecutorDemo {
  7. public static void main(String[] args) {
  8. ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
  9. for (int i = 0; i < 5; i++) {
  10. service.schedule(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println(Thread.currentThread().getName()+"执行操作");
  14. }
  15. },2, TimeUnit.SECONDS);
  16. }
  17. service.shutdown();
  18. }
  19. }

范例:观察间隔调度

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.Executors;
  3. import java.util.concurrent.ScheduledExecutorService;
  4. import java.util.concurrent.TimeUnit;
  5.  
  6. public class ExecutorDemo {
  7. public static void main(String[] args) {
  8. ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
  9. for (int i = 0; i < 5; i++) {
  10. service.scheduleAtFixedRate(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println(Thread.currentThread().getName()+"执行操作");
  14. }
  15. },2,3, TimeUnit.SECONDS);
  16. }
  17. }
  18. }

ExecutorService线程池处理方法

通过之前的线程池的演示可以发现,整个线程池的处理里面都是以ExecutorService接口的方法为核心展开的。所以如果要想理解线程池,还需要对整个接口的方法做一个小小的说明。

1、在Executor接口里面定义了有execute()方法:

  1. public interface Executor {
  2. void execute(Runnable command);
  3. }

这个方法接收的是Runnable,因为Runnable没有返回值,所以该方法的返回值为void。

范例:使用execute()方法来代替之前的submit():

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4.  
  5. public class ExecutorDemo {
  6. public static void main(String[] args) {
  7. ExecutorService service = Executors.newCachedThreadPool();
  8. for (int i = 0; i < 5; i++) {
  9. service.execute(new Runnable() {
  10. @Override
  11. public void run() {
  12. System.out.println(Thread.currentThread().getName()+"执行操作");
  13. }
  14. });
  15. }
  16. service.shutdown();
  17. }
  18. }

2、在ExecutorService接口里面的确提供有接收Runnable接口对象的方法,但是这个方法为了统一使用的是submit()。submit()重载了许多次,可以接收Runnable:

  1. public Future<?> submit(Runnale task) 

范例:使用ExecutorService接口的submit:

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.Future;
  5.  
  6. public class ExecutorDemo {
  7. public static void main(String[] args) throws Exception {
  8. ExecutorService service = Executors.newCachedThreadPool();
  9. for (int i = 0; i < 5; i++) {
  10. Future<?> future = service.submit(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println(Thread.currentThread().getName() + "执行操作");
  14. }
  15. });
  16. System.out.println(future.get()); //Runnable接口没有返回值,所以永恒为null
  17. }
  18. service.shutdown();
  19. }
  20. }

3、 submit()方法是可以接收Callable接口对象的

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.Callable;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Future;
  6.  
  7. public class ExecutorDemo {
  8. public static void main(String[] args) throws Exception {
  9. ExecutorService service = Executors.newCachedThreadPool();
  10. for (int i = 0; i < 5; i++) {
  11. Future<?> future = service.submit(new Callable<Object>() {
  12. @Override
  13. public Object call() throws Exception {
  14. return Thread.currentThread().getName() + "执行操作";
  15. }
  16. });
  17. System.out.println(future.get());
  18. }
  19. service.shutdown();
  20. }
  21. }

查看execute()方法的源码:

  1. public void execute(Runnable command) {
  2. if (command == null)
  3. throw new NullPointerException();
  4. int c = ctl.get();
  5. if (workerCountOf(c) < corePoolSize) {
  6. if (addWorker(command, true))
  7. return;
  8. c = ctl.get();
  9. }
  10. if (isRunning(c) && workQueue.offer(command)) {
  11. int recheck = ctl.get();
  12. if (! isRunning(recheck) && remove(command))
  13. reject(command);
  14. else if (workerCountOf(recheck) == 0)
  15. addWorker(null, false);
  16. }
  17. else if (!addWorker(command, false))
  18. reject(command);
  19. }

在这个方法里面主要区分三个概念:

  • task:是具体的线程执行任务,线程在追加线程池的时候没有进行启动;
  • worker:任务的执行需要worker来支持的,可以运行的worker受到“corePoolSize”限制;
  • reject:如果现在线程池已经满了或者关闭了,那么就会出现拒绝新线程加入的可能性。

4、Future线程模型设计的优势在于:可以进行线程数据的异步控制,但是在之前编写的过程严格来讲并不好,相当于启动了一个线程就获得了一个返回值,于是为了方便这些线程池中线程对象的管理,可以使用如下方法进行统一返回:

  1. public interface ExecutorService extends Executor {
  2. public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
  3. }

范例:使用invokeAny()方法

  1. package so.strong.mall.concurrent;
  2. import java.util.HashSet;
  3. import java.util.Set;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7.  
  8. public class ExecutorDemo {
  9. public static void main(String[] args) throws Exception {
  10. Set<Callable<String>> tasks = new HashSet<>(); //所有任务
  11. for (int i = 0; i < 10; i++) {
  12. final int temp = i;
  13. tasks.add(new Callable<String>() {
  14. @Override
  15. public String call() throws Exception {
  16. return Thread.currentThread().getName() + "执行任务,i=" + temp;
  17. }
  18. });
  19. }
  20. ExecutorService service = Executors.newCachedThreadPool(); //创建一个线程池
  21. String invokeAny = service.invokeAny(tasks); //执行任务
  22. System.out.println("返回结果:" + invokeAny);
  23. service.shutdown();
  24.  
  25. }
  26. }
  1. 返回结果:pool-1-thread-2执行任务,i=4

使用invokeAny()方法只会返回一个任务的执行操作

5、对于多个线程任务的执行结果,可以以list形式返回

  1. public interface ExecutorService extends Executor {
  2. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
  3. }

范例:使用invokeAll()方法

  1. package so.strong.mall.concurrent;
  2. import java.util.HashSet;
  3. import java.util.List;
  4. import java.util.Set;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.Future;
  9.  
  10. public class ExecutorDemo {
  11. public static void main(String[] args) throws Exception {
  12. Set<Callable<String>> tasks = new HashSet<>(); //所有任务
  13. for (int i = 0; i < 10; i++) {
  14. final int temp = i;
  15. tasks.add(new Callable<String>() {
  16. @Override
  17. public String call() throws Exception {
  18. return Thread.currentThread().getName() + "执行任务,i=" + temp;
  19. }
  20. });
  21. }
  22. ExecutorService service = Executors.newCachedThreadPool(); //创建一个线程池
  23. List<Future<String>> invokeAll = service.invokeAll(tasks); //执行任务
  24. for (Future<String> future : invokeAll) {
  25. System.out.println("返回结果:" + future.get());
  26. }
  27. service.shutdown();
  28.  
  29. }
  30. }

CompletionService线程池异步交互

  1. package java.util.concurrent;
  2. public interface CompletionService<V> {
  3. Future<V> submit(Callable<V> task);
  4. Future<V> submit(Runnable task, V result);
  5. Future<V> take() throws InterruptedException;
  6. Future<V> poll();
  7. Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
  8. }

线程池异步交互:CompletionService

  • 将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者submit()执行的任务,使用者take()已完成的任务,并按照完成任务的顺序处理它们的结果。
  • CompletionService依赖于一个单独的Executor来实际执行任务,在这种情况下,CompletionService只管理一个内部完成队列,在CompletionService接口里面提供有如下两个方法:
    •  设置Callable: 

      1. public Future<V> submit(Callable<V> task);
    • 设置Runnable:
      1. public Future<V> submit(Runnable task, V result); 

CompletionService是一个接口,如果要想使用这个接口可以采用ExecutorCompletionService这个子类

  1. public class ExecutorCompletionService<V> implements CompletionService<V>

ExecutorCompletionService的构造方法:

  1. public ExecutorCompletionService(Executor executor) {
  2. if (executor == null)
  3. throw new NullPointerException();
  4. this.executor = executor;
  5. this.aes = (executor instanceof AbstractExecutorService) ?
  6. (AbstractExecutorService) executor : null;
  7. this.completionQueue = new LinkedBlockingQueue<Future<V>>();
  8. }

CompletionService来控制所有线程池的操作以及数据返回,则应该使用这个类来进行线程池的提交处理。

  • 提交线程

    1. Future<V> submit(Callable<V> task);
  • 获取返回内容
    1. Future<V> take() throws InterruptedException;  

范例:使用CompletionService工具类

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.*;
  3.  
  4. public class ExecutorDemo {
  5. public static void main(String[] args) throws Exception {
  6. ExecutorService service = Executors.newCachedThreadPool();
  7. CompletionService<String> completions = new ExecutorCompletionService<>(service);
  8. for (int i = 0; i < 5; i++) {
  9. final int temp = i;
  10. completions.submit(new Callable<String>() {
  11. @Override
  12. public String call() throws Exception {
  13. return Thread.currentThread().getName() + "- i =" + temp;
  14. }
  15. });
  16. }
  17. for (int i = 0; i < 5; i++) {
  18. System.out.println(completions.take().get());
  19. }
  20. service.shutdown();
  21. }
  22. }

CompletionService操作接口的主要目的是可以去隐藏ExecutorService接口执行线程池的处理,不在需要关心novkeAny(), invokeAll()的执行方法了。

ThreadPoolExecutor线程池执行者

线程池的创建主要依靠的是一个类完成的:ThreadPoolExecutor,下面以无限量线程池为例做一个说明:

  1. public static ExecutorService newCachedThreadPool() {
  2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  3. 60L, TimeUnit.SECONDS,
  4. new SynchronousQueue<Runnable>());
  5. }

观察ThreadPoolExecutor类的构造方法:

  1. public ThreadPoolExecutor(int corePoolSize,
  2. int maximumPoolSize, //最大的线程大小
  3. long keepAliveTime, //存活的时间
  4. TimeUnit unit,
  5. BlockingQueue<Runnable> workQueue, //工作队列
  6. ThreadFactory threadFactory,
  7. RejectedExecutionHandler handler) {
  8. if (corePoolSize < 0 ||
  9. maximumPoolSize <= 0 ||
  10. maximumPoolSize < corePoolSize ||
  11. keepAliveTime < 0)
  12. throw new IllegalArgumentException();
  13. if (workQueue == null || threadFactory == null || handler == null)
  14. throw new NullPointerException();
  15. this.corePoolSize = corePoolSize;
  16. this.maximumPoolSize = maximumPoolSize;
  17. this.workQueue = workQueue;
  18. this.keepAliveTime = unit.toNanos(keepAliveTime);
  19. this.threadFactory = threadFactory;
  20. this.handler = handler;
  21. }

范例:创建属于自己的线程池

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.*;
  3.  
  4. public class ExecutorDemo {
  5. public static void main(String[] args) throws Exception {
  6. BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
  7. ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 5, 6L, TimeUnit.SECONDS, queue);
  8. for (int i = 0; i < 2; i++) {
  9. final int temp = i;
  10. pool.execute(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println("[" + Thread.currentThread().getName() + "]任务开始执行-" + temp);
  14. try {
  15. TimeUnit.SECONDS.sleep(2);
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. System.out.println("[" + Thread.currentThread().getName() + "]任务结束执行-" + temp);
  20. }
  21. });
  22. }
  23. pool.shutdown();
  24. }
  25. }

在线程池中存在拒绝策略的概念,所谓的拒绝策略指的是线程池满了之后的其他等待线程的处理状态。在ThreadPoolExecutor类里面提供有一些“RejectedExecutorHandler”子类。如果现在被拒绝会出现“拒绝异常”(默认AbortPolicy)、对于给出的几种拒绝策略如下:

  • AbortPolicy:默认实现,当任务添加到线程池中被拒绝时,会抛出拒绝异常"RejectedExecutionException";
  • DiscardPolicy:当将任务添加到线程池中被拒绝的时候,线程池将直接丢弃该拒绝的任务;
  • DiscardOldestPolicy:当被拒绝时,线程池会放弃等待队列中时间最长的未被处理的任务,然后将被拒绝的任务添加到队列之中;
  • CallerRunsPolicy:当任务被拒绝的时候,会在线程池当前正在运行的Thread线程之中处理该任务(加塞)。

范例:修改一下侧率

  1. package so.strong.mall.concurrent;
  2. import java.util.concurrent.*;
  3.  
  4. public class ExecutorDemo {
  5. public static void main(String[] args) throws Exception {
  6. BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
  7. ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 6L, TimeUnit.SECONDS, queue, Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
  8. for (int i = 0; i < 5; i++) {
  9. final int temp = i;
  10. pool.execute(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println("[" + Thread.currentThread().getName() + "]任务开始执行-" + temp);
  14. try {
  15. TimeUnit.SECONDS.sleep(2);
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. System.out.println("[" + Thread.currentThread().getName() + "]任务结束执行-" + temp);
  20. }
  21. });
  22. }
  23. pool.shutdown();
  24. }
  25. }
  1. Exception in thread "main" [pool-1-thread-1]任务开始执行-0
  2. [pool-1-thread-2]任务开始执行-3
  3. java.util.concurrent.RejectedExecutionException: Task so.strong.mall.concurrent.ExecutorDemo$1@6da13f3d rejected from java.util.concurrent.ThreadPoolExecutor@45d45d18[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
  4. at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)
  5. at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
  6. at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
  7. at so.strong.mall.concurrent.ExecutorDemo.main(ExecutorDemo.java:15)

  

由于只设置了一个CorePoolSize,所以当多余的任务出现之后将采用设置的默认的拒绝策略:“new ThreadPoolExecutor.AbortPolicy()”会出现“RejectedExecutionException"异常,如果出现拒绝之后丢弃该拒绝的任务,那么也可以将拒绝策略修改为:

  1. ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 6L, TimeUnit.SECONDS, queue, Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());

对于拒绝策略最简单的解释就是:线程池中的corePoolSize满了,再追加的任务的处理方案。

PS:阿里巴巴Java开发手册——并发处理第4条

【强制】线程池不允许使用Executors创建,而是通过ThreadPoolExecutor的方式创建,这样的处理方式能让编程代码的工程师更加明确线程池的运行规则,规避资源耗尽的风险。

说明:Executors返回的线程池对象的弊端如下:

  1. FixedThreadPool和SingleTheadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM;
  2. CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

JUC——线程池的更多相关文章

  1. 【JUC】JUC线程池框架综述

    一.前言 在分析完了JUC的锁和集合框架后,下面进入JUC线程池框架的分析,下面给出JUC线程池的总体框架,之后再逐一进行分析. 二.JUC线程池框架图 说明:从上图可知,JUC线程池框架中的其他接口 ...

  2. java多线程系类:JUC线程池:03之线程池原理(二)(转)

    概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...

  3. java多线程系类:JUC线程池:02之线程池原理(一)

    在上一章"Java多线程系列--"JUC线程池"01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我 ...

  4. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  5. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

  6. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  7. Java多线程系列--“JUC线程池”04之 线程池原理(三)

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...

  8. Java多线程系列--“JUC线程池”05之 线程池原理(四)

    概要 本章介绍线程池的拒绝策略.内容包括:拒绝策略介绍拒绝策略对比和示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3512947.html 拒绝策略 ...

  9. Java - "JUC线程池" 架构

    Java多线程系列--“JUC线程池”01之 线程池架构 概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介 ...

  10. Java - "JUC线程池" ThreadPoolExecutor原理解析

    Java多线程系列--“JUC线程池”02之 线程池原理(一) ThreadPoolExecutor简介 ThreadPoolExecutor是线程池类.对于线程池,可以通俗的将它理解为"存 ...

随机推荐

  1. Alpha 冲刺报告(10/10)

    Alpha 冲刺报告(10/10) 队名:洛基小队 峻雄(组长) 已完成:阿尔法版的ppt 明日计划:总结阿尔法版的问题 剩余任务:角色属性脚本的完整版本 困难:缺乏编码经验,编码进度比较慢 ---- ...

  2. 【原创】uWSGI http和http-socket说明

    http 和 http-socket的使用上有一些区别: http: 自己会产生一个http进程(可以认为与nginx同一层)负责路由http请求给worker, http进程和worker之间使用的 ...

  3. node(一)安装nodejs最新版到debian,ubuntu,mint系统

    从官网得到,测试可以使用,本机为linux mint18 官网原文链接在此 //     直接使用sudo apt install nodejs安装的版本较老,而且命令必须使用nodejs //   ...

  4. virtualbox+vagrant学习-2(command cli)-8-vagrant Package命令

    Package 格式: vagrant package [options] [name|id] 这将当前正在运行的VirtualBox或Hyper-V环境打包到一个可重用的box中.如果provide ...

  5. 机器学习中的特征缩放(feature scaling)

    参考:https://blog.csdn.net/iterate7/article/details/78881562 在运用一些机器学习算法的时候不可避免地要对数据进行特征缩放(feature sca ...

  6. mapent

    package test12; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import ja ...

  7. 传入一个integer数组,取出最大、最小值

    /** * <p> * 传入一个integer数组,取出最大值 * </p> * @author yunns 2015年11月19日 * @param array * @ret ...

  8. 【VSC】git+github/码云+VSCode

    VSCode中使用git,参见. (零)Git安装 在初次使用时如果本地没有安装git会提示先安装git,然后重启vscode. (一)本地操作项目前提: 1)若本地没有git拉取下来的项目,用git ...

  9. 在CentOS/RHEL 6.4上安装Chromium

    是的,之前Google就说了,由于CentOS/RHEL 6已经是过期的系统,所以不再会有Chrome了.虽然后来由于引起了社区的抗议,从而改口,不再提CentOS/RHEL 6是过期系统了:但是,目 ...

  10. 学习笔记——OS——引论

    学习笔记--OS--引论 操作系统的定义 操作系统是一组管理计算机硬件资源的软件集合: 用户和计算机硬件之间的接口 控制和管理硬件资源 实现对计算机资源的抽象 计算机系统硬件 冯诺依曼体系结构和哈佛结 ...