JUC(一):进程与线程
JUC(一):进程与线程
小吴顶呱呱一、进程与线程
1.1 进程
进程
(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的 描述,进程是程序的实体。
1.2 线程
线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之 中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流, 一个进程中可以并发多个线程,每条线程并行执行不同的任务。
1、线程是独立调度和分派的基本单位。2、同一进程中的多条线程将共享该进程中的全部系统资源。3、一个进程可以有很多线程,每条线程并行执行不同的任务。可并发执行。
1.3 创建线程的几种方式
-
继承Thread类:创建一个类继承Thread类,并重写run()方法,在run()方法中定义线程要执行的任务。
1
2
3
4
5
6
7
8
9
10
11public class MyThread extends Thread {
public void run() {
System.out.println("This is a thread created by extending Thread class.");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
} -
实现Runnable接口:创建一个类实现Runnable接口,并实现其run()方法,在run()方法中定义线程要执行的任务。然后将实现了Runnable接口的类作为参数传递给Thread类的构造方法创建线程。
1
2
3
4
5
6
7
8
9
10
11public class MyRunnable implements Runnable {
public void run() {
System.out.println("This is a thread created by implementing Runnable interface.");
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
} -
使用匿名内部类:可以直接在创建线程的地方使用匿名内部类来实现线程,省去了定义一个单独的类的步骤。
1
2
3
4
5
6
7
8
9
10
11public class AnonymousThread {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
public void run() {
System.out.println("This is a thread created using anonymous inner class.");
}
});
thread.start();
}
} -
使用线程池:通过Executor框架可以创建线程池,然后将任务提交给线程池执行,可以重复利用线程,提高性能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new MyRunnable();
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("All threads are finished");
}
} -
使用Callable和Future:Callable接口类似于Runnable接口,但是它可以返回结果,并且可以抛出异常。Future接口可以获取Callable的返回结果,可以用于异步获取线程执行结果。
步骤1:创建实现Callable接口的类
步骤2:创建一个类对象:Callable callable = new Callable();
步骤3:由Callable创建一个FutureTask对象:
FutureTask
future = new FutureTask (callable); 注释:FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了Future和Runnable接口。
步骤4:由FutureTask创建一个Thread对象:Thread thread = new Thread(future);
这里为什么可以new Thread(future)
Thread的构造函数:
1
2
3public Thread(Runnable target) {
this(null, target, "Thread-" + nextThreadNum(), 0);
}1
2
3public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> 因为FutureTask间接实现了Runnable接口
步骤5:启动线程:thread.start();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<String> callable = new Callable<String>() {
public String call() {
return "This is a thread created using Callable and Future";
}
};
FutureTask<String> future = new FutureTask<String>(callable);
Thread thread = new Thread(future);
thread.start();
System.out.println(future.get());
}
}
1.4 Callable和Runnable
实现了Runnable和Callable的类都可以当作线程任务,那么这俩接口有什么区别:
- Runnable接口是java1.1就有的,Callable接口是java1.5才有的,可以认为Callable接口是升级版的Runnable接口;
- Runnable接口里面的线程任务是在run方法里面,而Callable接口是call方法
- Callable接口的任务执行后会有返回值,Runnable接口的任务无返回值(void);
- callable接口中的call方法支持抛出异常,而run方法不可以
- 加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用ExecutorService的submit方法
- 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。Future对象封装了检查计算是否完成、检索计算的结果的方法,而Runnable接口没有。
总的来说:Callable
类似于Runnable
,但它可以返回一个结果,而且还能抛出异常。常用于与线程池组合使用,组成了一套java提供的异步框架。