进程:系统分配资源的单位;
线程:处理器任务调度和执行的单位,线程之间共享进程资源。
学习大纲:
创建线程:
一、继承Thread类
二、实现Runnable接口
三、创建线程池:
线程池需要了解一个类和一个接口:Executors:工具类、线程池的工厂类;ExecutorService:真正的线程池接口,其子类为ThreadPoolExecutor。
池:即使池子(Pool),即我们可以在线程池中定义多个线程。
Executors:
工具类、线程池的工厂类,用于创建并返回不同类型的线程池
Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池
Executors.newFixedThreadPool(n):创建一个可重用固定线程数的线程池
Executors.newSingleThreadExecutor() :创建一个只有一个线程的线程池
Executors.newScheduledThreadPool(n):创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
ExecutorService:
真正的线程池接口,需要掌握三个方法。
方法详情:
execute(Runnable runnable):只能用来实现Runnable接口
sumbit(Callable callable):一般用来实现Callable接口,但是也可是实现Runnable接口
showdown():关闭连接池
想知道Callable是什么,往下学习!!!
public class DemoThreadPool02 {
public static void main(String[] args) {
//这里其实引用了多态的写法,ExecutorService是一个接口不能创建对象,
//所以这里的service其实是ExecutorService接口的实现类对象ThreadPoolExecutor
ExecutorService service = Executors.newFixedThreadPool(5);
// System.out.println(service.getClass());//获取当前对象所属的类的路径class java.util.concurrent.ThreadPoolExecutor
ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) service;
FutureTask futureTask = new FutureTask(new PrintPrimeNumber());
service.submit(futureTask);//执行实现Callable接口的实现类对象的线程
service.execute(new PrintPrimeNumber02());//执行实现Runnable接口的实现类的线程
service.shutdown();//关闭连接池
}
}
/**
* 打印100以内的质数
*/
class PrintPrimeNumber02 implements Runnable{
@Override
public void run() {
for (int i = 2; i <= 100; i++) {
boolean isFlag = true;
for (int j = 2; j <= Math.sqrt(i); j++) {
if (i % j == 0){
isFlag = false;
break;
}
}
if (isFlag == true)
System.out.println(i);
}
}
}
/**
* 打印100-200以内的质数
*/
class PrintPrimeNumber implements Callable{
private int num = 100;
@Override
public Object call() throws Exception {
for (int i = 100; i <= 200; i++) {
boolean isFlag = true;
for (int j = 2; j <= Math.sqrt(i); j++) {
if (i % j == 0){
isFlag = false;
break;
}
}
if (isFlag == true)
System.out.println(i);
}
return null;
}
}
四、实现Callable接口:
实现Callable接口有别于前两种创建线程的方式,实现Callable接口不是重写/实现run()而是实现call()方法,并且有返回值。
class Demo implements Callable {
//有Object类型的返回值,如果分线程需要该线程提供值,然后继续线程时可以使用实现Callable接口
//如果不想要返回值,直接让返回值为null即可。
@Override
public Object call() throws Exception {
return null;
}
}
实现Callable接口需要结合Future接口使用,使用Future接口的唯一实现类FutureTask去接收返回值,注意此时并没有开启线程,如果开启线程的话还需要借助Thread类去,开始线程调用call()方法。
FutureTask实现类底层实现了RunnableFuture接口,而RunnableFuture接口底层继承自Runnable接口和Future接口…所以在使用new Thread类开启线程底层运用了和实现Runnable接口类似的效果。
案例:
public class DemoCallable02 {
public static void main(String[] args) {
ArraySums arraySums = new ArraySums();
FutureTask futureTask = new FutureTask(arraySums);
//可是使用下面的方法一气呵成
// FutureTask futureTask = new FutureTask(new ArraySums());
Thread thread = new Thread(futureTask);
thread.start();
try {
Object sum = futureTask.get();
System.out.println("100以内的偶数和为:" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//计算100以内的偶数和
class ArraySums implements Callable {
private int i = 1;
private int sum = 0;
@Override
public Object call() throws Exception {
while (true){
if (i <= 100){
if (i % 2 == 0){
System.out.println(i);
sum += i;
}
i ++;
}else {
break;
}
}
return sum;
}
}
案例说明:
如果我们不使用new Thread.start(),就不会执行call()方法中的内容,也就是还没有启动线程;
使用FutureTask实现类,目的是接收call()方法的返回值…FutureTask实现类中的get()方法会获取call()方法的返回值…另外FutureTask实现类中也定了很多对接call()的方法…
如果不用接收call()方法的返回值,可以将返回值设置为null,不用使用get()方法。
实现Callable接口的好处:
Callable接口是有泛型的,可以规范用户的存储;
Callable接口中的call()方法是有返回值的,可以方便线程间的通信;
Callable接口中的call()方法是可以抛异常的,可以在后续异常进行捕获和处理。
欢迎关注微信公众号:小红的成长日记,一起学Java!