java高并发编程(多线程详解)-多线程基础
什么是线程
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
创建线程的四种方式
1. 继承Thread类创建线程
使用:
- 继承Thread类,然后实现其run()方法。
- 通过new的方式调用start()方法。
特点:继承,继承此类就不能在继承其他类,而实现Runnable接口则可以避免这种缺陷。
示例代码如下:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承Thread类的创建方式");
}
}
public class Test {
public static void main(String args[]) {
//启动继承Thread类创建的线程对象
MyThread t1 = new MyThread();
t1.start();
}
2. 实现Runnable接口创建线程
使用:
- 实现Runnable 中的run()方法。
- 将Runnable接口的子类实体传入thread构造方法中,通过thread.start()进行调用。
特点:
- 接口实现的方式进行使用,更加的适用。同时Runnable内部的代码可以被多个线程(Thread实例)共享,适用于多个线程处理同一资源的情况。
- 所有接口创建方式都会使用到Runnable,Thread类(Thread 实现了Runnable接口),方式三中的Future也实现了Runnable的接口。
注:因为所有的线程创建都来源于Runnable接口,如果说线程的创建方式只有一种,那么这种方式就是是Runnable。
特点:继承,继承此类就不能在继承其他类,而实现Runnable接口则可以避免这种缺陷。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口");
}
public class Test {
public static void main(String args[]) {
//启动实现Rinnable接口创建的线程对象
Thread t2 = new Thread(new MyRunnable());
t2.start();
}
3. 使用Callable和FutureTask创建线程
java5开始,提供了Callable接口,是Runable接口的增强版。同样用Call()方法作为线程的执行体,增强了之前的run()方法。因为call方法可以有返回值,也可以声明抛出异常。
特点与简单说明
Callable
是一个接口和Runnable类似,使用者需要实现call()方法,在实现call方法时可以返回一个值给调用方。
FutureTask
该类是为创建Callable线程而诞生的,用于管理和创建Callable方式创建的线程,Callable能返回值也是因为这个FutureTask的内部管理和标记二实现的。
FutureTask 实现了Future和Runable接口,起作用:
- Futurn:用于管理标记其状态以及获取返回值(get()方法)。
- Runable:用于创建线程。(Callable接口不具备创建线程的能力)
代码示例
- 实现且定义Callable子类。
- 通过FutureTask进行调用,创建,监督线程。
import java.util.concurrent.Callable;
//Callable<String> -》 声明返回类型String
public class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id=id;
}
@Override
public String call() throws Exception {
return "Callable return Information: "+id;
}
}
//Runnable是执行工作的独立任务,但是它不返回任何值。在Java SE5中引入的Callable是一种具有类型参数的泛型,它的类型参数表的是从方法call()中返回的值,并且必须使用ExecutorServices.submit()方法调用它,下面是一个简单示例。
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class CallableTest {
public static native void sleep(long millis) throws InterruptedException;
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("使用方式一");
// //通过借助FutureTask来 调用 运行 获取线程返回数据
// //1.创建FutureTask并且传入一个callable线程
FutureTask futureTask = new FutureTask(new TaskWithResult(66));
// //2.运行run方法
futureTask.run();//运行
System.out.println(futureTask.isCancelled());//是否被取消
System.out.println(futureTask.isDone());//是否已经结束
// //3.获取并打印返回值
System.out.println(futureTask.get());
}
}
//第二种方式:通过Excutors创建线程
public static void main(String[] args) throws ExecutionException, InterruptedException {System.out.println("使用方式二");
//使用Executors来运行callable线程并获取返回结果
//1.获取ExecutorService对象(就是一个线程池)
ExecutorService exec=Executors.newCachedThreadPool();
//2.创建线程并且提交(submit理解为 run() ),获取Future(Future 存储了线程的状态和结果值)
for(int i=0;i<5;i++) {
Future<String> submit = exec.submit(new TaskWithResult(i));
//线程睡眠10毫秒
Thread.sleep(10);
// 10毫秒后判断线程是否运行完成,并打印结果
if(submit.isDone()){System.out.println(submit.get());}
}
4. 使用线程池框架创建线程的多种方式
Executors
java中提供了一个静态工厂方法来创建不同的线程池: Executors
- 通过Executors创建无返回值的线程:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CreateThreadByExecutor {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
executorService.shutdown();
}
}
- 通过Executors创建有返回值的线程:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CreateThreadByExecutors2 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(5);
Future<String> future1 = executorService.submit(() -> {
return Thread.currentThread().getName();
});
Future<String> future2 = executorService.submit(() -> {
return Thread.currentThread().getName();
});
System.out.println(future1.get());
System.out.println(future2.get());
executorService.shutdown();
}
}
TThreadPoolExecutors
线程池这块东西不少我先写到这里。这得注意的是excutor创建线程的方式并不可取。原因如下
具体待定。。。