最近想再系统地复习一遍并发,随便再把以前整理的笔记整理为博客。
概念
了解线程前先要了解一下进程,进程是程序的一次执行过程,是系统运行的基本单位,其可以拥有资源,一个进程在执行期间会执行一系列的命令。
什么是线程?
线程是是比进程更小的一个执行的单位,一个进程中有多个线程。
线程在执行时是不断进行切换的,一个进程在运行时可能随时停止去运行另外一个线程。
一个线程在执行时有多种状态,有新建、就绪、运行、阻塞、等待、死亡六种状态。
在《java并发编程的艺术》中有下图,形象地说明了线程运行时的状态转换。
创建线程
在java中创建线程常用的有三种方式
继承Thread类
创建一个线程类最简单的方式就是直接继承Thread类并重写run方法。
例如:
public class Thread1 extends Thread {
@Override
public void run() {
System.out.println("run" );
}
}
想直接创建线程,直接使用Thread类也是可以的,但也要重写run方法
public static void main(String[] args) {
Thread x = new Thread() {
public void run(){
System.out.println("run");
}
};
}
为了简便,我们这样创建线程时可以使用lambda表达式的形式创建,例如上面的方法可以变为
public static void main(String[] args) {
Thread x = new Thread(()->System.out.println("run"));
}
当里面的代码超过一行时需要加上{},例如
public static void main(String[] args) {
Thread x = new Thread(()->{
System.out.println("run1");
System.out.println("run2");
});
}
如果想要启动线程可以使用.start为进入就绪状态,进入就绪态后被系统选中就可以进入执行态。
使用Runnable
首先我们可以使用实现Runnable接口的方式创建一个线程类
public class Thrad2 implements Runnable {
@Override
public void run() {
System.out.println("run" );
}
}
其次我还可以写一个匿名内部类去实现Runnable接口的方法,获取一个runnable对象作为一个参数在Thread类中使用来创建一个线程
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("run");
}
};
Thread y = new Thread(runnable);
我们可以看一下Runnable接口的源码,可以发现其只有一个可以实现的方法就是run,通过实现这个方法作为我们线程执行时的操作
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
使用这个方法我们可以看成runnable中去线程执行的任务,在使用Thread时才会真正创建线程。
它将线程与其执行的任务分开来创建。
使用FutureTask
使用这个方法创建线程可以接收callable类对象的参数,把运行的代码放在callable中的calll方法中,并且还可以使线程具有返回结果。
例如:
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("run");
return 100;
}
};
FutureTask<Integer> task = new FutureTask<>(callable);
Thread m = new Thread(task);
我们先来看callable接口,其和runnable很像,但是其拥有返回值并且可以抛出异常。
@FunctionalInterface
public interface Callable<V> {
/**
* 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;
}
然后我们查看FutureTask源码,可以发现FutureTask其实现了RunnableFuture<V>接口
public class FutureTask<V> implements RunnableFuture<V>
而RunnableFuture<V>接口其实是继承了Runnable和Future<V>,而Future<V>接口就可以返回执行结果。
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}