多线程,多线程的实现方式,线程的创建方式
线程
线程的创建方式 //注意看代码里面的注释,都是我手敲的说明
第一种,直接继承 Thread类,重写run()方法
//lambda
Thread thread = new Thread(()->{
System.out.println("直接new Thread类");
});
thread.start();//启动
//jdk1.7
class MyThread extends Thread{
@Override
public void run(){
System.out.println("继承thread");
}
}
new MyThread().start();//启动
第二种,实现Runnable接口
class MyThread2 implements Runnable{
@Override
public void run(){
System.out.println("实现runnable");
}
}
new Thread(new MyThread2()).start();//启动
第三种,实现Callable接口
class MyThread3 implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("实现Callable");
return "ss";
}
}
这里着重讲一下Callable接口实现启动的方式
因为Callable方式比较特殊,它允许线程有返回值,并且可以抛出异常
一.线程池情况下启动线程有两种方式
线程池启动有两种submit 和execute 两种
和
这里就不多说线程池方面的了,大家看一下参数类型就可以了,
二.通过Thread类进行启动
启动线程需要Thread类的start()方法,需要把线程去装载到Thread类,而Thread类的构造器可以接收Runnable 类型的,不能接收Callable类型的
那么就要引出FutureTask类.
FutureTask 它对Callable进行了包装并且实现了RunnableFuture ,RunnableFuture接口又继承了Runnable接口.那么我们把Callable封装成FutureTask不就可以被Thread 构造器加载了吗
FutureTask 它有个内部变量类Callable
在他执行run()方法的时候进行了调用Callable的.call()方法,展示一下源码
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();//就是这个地方
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
// -----
//再展示一下FutureTask的构造器,方便下面讲解创建方式
//传递一个Callable对象进来
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
/**
传递一个Runnable 对象进来,
并且传递一个最终返回的值(前面说了FutureTask有返回值),
这个值并未做修改传什么返回什么
**/
public FutureTask(Runnable runnable, V result) {
//这里进行了对runnable封装成callable
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
//那么看封装方法
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);//继续跟进此方法
}
//跟进之后就是这个了,传递的result直接赋值了this.result
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {//跟进的方法
this.task = task;
this.result = result;//进行赋值
}
//被执行的call(),忘记了看上面run()方法
public T call() {
task.run();
return result;//这里进行了直接返回.并未做处理
}
}
//那么下面开始讲解使用FutureTask创建线程Callable
//我最近在熟悉lamba表达式,看不懂就看下面jdk1.7创建方式
FutureTask<String> ft3 = new FutureTask<String>((Callable<String>)()->{
System.out.println("FutureTask,创建有返回值的线程");
return "张三";
});
ft3.get();//进行获取返回的值 这一句抛了异常要进行cry catch
//jdk1.7 泛型是指要返回的数据的类型
FutureTask<String> ft1 = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
return "李四";
}
});
封装成FutureTask 之后就可以被Thread所加载使用了
new Thread(FutureTask).start();//启动