当前位置: 主页 > JAVA语言

java线程-java 线程队列

发布时间:2023-03-23 22:05   浏览次数:次   作者:佚名

第一种: 通过继承Thread类创建线程

第二种: 通过实现Runnable接口创建线程

这两种早已烂记于心,这里就不作过多的介绍, 主要介绍其源码

Thread类 implements Runnable

java 线程队列_java线程中有线程_java线程

thread空线程的run方法 是判断target是否存在实,再执行target实例中的run方法

public void run(){
    if(this.target != null){
           this.target.run();
     }
}

通过实现Runnable接口, 并且通过thread构造函数创建线程的方法

Runnable runnable = new Runnable(){...重写run方法};
Thread thread_one = new Thread(runnable);
Thread thread_two = new Thread(runnable);

java线程中有线程_java线程_java 线程队列

如果创建多个线程,实质是多个线程引用同一个target 实例

对比两种方式的区别:

通过继承Thread类实现多线程的方式由于单继承的局限性java线程, 不能再继承其他类, 只能完成各自的任务

通过实现Runnable接口实现多线程的方式能更好的做到并发完成同一个任务, 因为访问的是同一个target, 实现了共享数据

总之,在大多数情况下,都偏向于通过实现Runnable接口创建多线程

第三种: 使用Callable接口 和 FutureTask类创建线程

由于Thread类和Runnbale接口中的run方法没有返回值, 所以这两种方式不能获取异步执行的结果

Callable接口

java 线程队列_java线程中有线程_java线程

package java.util.concurrent;
@FunctionalInterface
public interface Callable{
    V call() throws Exception;
}

@FunctionalInterface 注解标注在接口上, 表示此接口为"函数式接口"

函数式接口: 只有一个抽象方法的接口

此注解只是方便编译器进行检查, 不加也不会影响. 如果加了注解但该接口不是函数式接口,编译器会报错

Callable接口是泛型接口 ,也是函数式接口

call()抽象方法还有一个Exception的异常声明, 容许方法内的异常直接抛出,并且可以不予捕获

java线程_java 线程队列_java线程中有线程

Future接口,RunnableFuture接口java线程,以及FutureTask实现类都是位于 java.util.concurrent包下

java 线程队列_java线程_java线程中有线程

V get() 用于阻塞性得到异步执行的结果. 此方法是阻塞性的,异步未执行完会处于阻塞状态

Object outcome用于保存call()方法的异步执行结果. get()会获取

创建线程的具体步骤

class ReturnableTask implements Callable{
      public long call() throws Exception{
             //线程要执行的代码
     }      
}    
public static void main(String args[]) throws InterruptedException{
    ReturnableTask task  = new new ReturnableTask();
     Futuretask FutureTask = new Futuretask(task);
    Thread thread = new Thread(FutureTask,"returnableThread");  
    thread.start();
    System.out.println(FutureTask.get());   //得到异步执行结果
}

下图为具体实现过程

java线程_java线程中有线程_java 线程队列

两个线程处于并发状态, 默认异步执行

看起来两个线程是同时进行,实质上是不是, 单个进程在同一时间只能执行一个进程,由于分给线程的时间片非常短(线程切换毫秒级),所以以为是同时

java 线程队列_java线程_java线程中有线程

并发执行的消息通信机制分为同步和异步, 这些就不做过多解释

总之,图上的两个线程不是同时运行

第四种: 通过线程池创建线程

通过Thread创建线程在执行完就被销毁了, 不可服用. 在高并发场景中, 频繁创建线程是非常消耗资源的,通过线程池创建线程可以对已经创建好的线程进行复用

Executors 静态工厂类 用于创建不同的线程池java.util.concurrent;

//创建一个包含三个线程的线程池
private static ExecutorService pool = Executors.newFixedThreadPool(3);

Executor接口

void executo(Runnable command);//执行Runnable类型

java线程_java线程中有线程_java 线程队列

ExecutorService extends Executor

Future submit(Callable task)//提交callable类型以执行

Future submit(Runnable task)//提交Runnable类型以执行

具体实现

main
Future future  = pool.submit(new RuturnableTask());
Long result = (Long) future.get();     //得到异步执行的结果

execute() 与 submit() 执行线程方法的区别

execute()只能执行Runnable, 并且无返回值

submit() 既能执行Runnable又能执行callable, 并且有返回值

注: 实际生产环境中禁止使用Executors创建线程池