Ansi Colors

在Bash/Zsh里面给命令行输出添加颜色,可以使用ANSI的控制字符串。

基本上能被所有终端都支持的颜色是16种。

Fast into Graphviz

Graphviz - Graph Visualization Software 由 AT&T 出品, 是一种结构化信息的可视化方式,也是一套开放源代码软件,可以被广泛地使用于网络拓扑、软件工程、数据库设计、机器学习等方向的图表展示。

Graphviz 1.2D 及之前的版本使用了 AT&T 代码许可证 (the AT&T Source Code Agreement),之后的版本使用了EPL (The Eclipse Public License) 。

Graphviz 是一款面向程序员的绘图软件,不仅体现在其设计和使用方式上,还体现在其文档上 :)

Learning Java Concurrency - Executors(1) ExecutorService

回过头来看Thread类,其实可以发现该类是对一件任务的抽象。通过将要完成的任务抽象出来用Thread或者Runnable来表示,然后委托给另外的线程来处理。Thread类在这里充当的是任务执行者的角色,表示一个执行任务的线程。

有时候,任务是不是由另一个线程执行并不重要,甚至于由几个线程共同完成我们也并不在意,我们只关心任务被完成了。任务这个概念已经被抽象的很好了:Runnable;接下来要抽象出任务执行者这个概念了。

Java提供了另一个接口Executor来真正地抽象任务执行者这个概念:线程池。怎么理解呢,看一下Executor接口的代码就好了。

Learning Java Concurrency - FutureTask & Callable

Java的java.util.concurrent包里面提供了多线程并发和同步的支持。

最开始的时候,多线程被认为是执行任务的手段,也就是说,我启动一个新线程来执行代码,至于资源共享、线程同步等可以用锁、同步器等解决。所以Thread类和Rannable接口暴露了一个void run()方法来提供自定义行为。

但慢慢地,人们开始发现如果自定义的线程是计算结果的,那我怎么来拿到计算之后的结果呢?另外,我得知道什么时候计算结束了,如果计算的时间太长了,我也想能够终止计算线程的执行。这些需求其实用基本的多线程工具也可以实现,但是过程比较繁琐;而且这些需求有一段时间又特别普遍。终于,jdk 1.5开始引入了Callable接口和Future接口,用于支援有返回值的计算任务。

Learning Java Concurrency - Thread & Runnable

Java并发多线程的第一课,应该就是Thread了。顾名思义,Thread就是一个线程。线程是很底层的一个概念,在不同的操作系统上实现的模型和细节并不相同,甚至于可以说天差地别;但是总体来说,线程是比进程更细粒度的操作系统调度的单位,线程有自己的运行栈,但是同一个进程的线程共享方法区和堆区数据。

对于进程和线程的差别,有一种说法是:线程是操作系统调度的基本单位,而进程是操作系统分配运行资源的基本单位。

Java中对线程作了很好的封装:Thread类。Thread类的使用非常简单。

public class ThreadCase {
    private static class EchoThread extends Thread {
        private final String word;

        public EchoThread(final String word) {
            this.word = word;
        }

        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                System.out.println(this.getName() + " echos " + word);
            }
        }
    }

    public static void main(String [] _args) {
        final Thread echo1 = new EchoThread("First");
        final Thread echo2 = new EchoThread("Second");

        System.out.println("Main thread started!");

        echo1.start();
        echo2.start();

        joinThread(echo1);
        joinThread(echo2);

        System.out.println("Main thread finished!");
    }

    private static void joinThread(final Thread th) {
        try {
            th.join();
        } catch (InterruptedException e) {
            System.out.println(th.getName() + " interrupted!");
        }
    }
}

可以很明显地发现:

  • main负责启动其他线程,main本身也是一个线程
  • 线程的调度是难以预料的,echo1echo2的输出结果相互交错可以看出这一点
  • 线程之间可以进行同步控制,使用Thread.join()方法可以强制等待另一个线程结束
  • 自定义线程行为只需要重新实现Thread.run()方法即可
  • 线程的启动入口是Thread.start()方法,不要直接运行Thread.run()方法
  • Thread类是一个class(与interface相对应),意味着自定义线程类不能继承别的父类