Java线程的使用方法

简介: 在上面的demo中,当执行到new Thread(futuretask).start()的时候,后台就会新建一个线程异步去执行call函数,而不等call执行完,当前代码会继续执行下去。但是特别需要注意的一点是,当你用futuretask.get()来获取线程执行结果的时候,如果此刻call() 还没执行完,futuretask.get()会一直阻塞下去等待返回结果。

大学的时候就顾着搞acm了,没写过工程,尤其是多系统协作的工程。工作中遇到一种场景,我自己代码需要多次调用别的系统api,http的接口rt在几十毫秒左右,我必须在几百毫秒内完成上百次的查询,串行的单线程代码不可能完,所以不可避免需要使用到线程,在java里线程的实现方方式有三种 Runnable Thread Callable。

 Runnable和Callable都是接口,Thread是类,但要是看下这三者的代码,其实发现最底层都和Runable有关,所以我们先来看下 Runnable


public interface Runnable {
    public abstract void run();
}


 Runable只定义了run一个函数,这个函数就是线程执行时调用的函数了。下面我展示个Runable的demo。

 Thread其实也实现了Runable接口,如果用Thread,重写run函数后就可以直接启动线程了。

 之前有种印象,Runable的使用频次要高于Thread,后来上网查了下,其实并不是用Thread会带来什么问题,而且由于java的特性,无法实现多继承,如果你用Thread就没办法继承其他类了,就会限制到你写代码的灵活性,而接口没有这个问题。

 Thread类中有好多native方法,我猜是和操作系统做交互用的,毕竟java 的线程最终还是映射到系统进程实现的(具体可参考《深入理解java虚拟机》一书,看过一次由于没啥概念,都忘记了)。

 下面代码展示下Thread和Runnable的具体使用方法。


//实现Runnable接口或者继承Thread类并实现run方法都是可以的

//public class ThreadTest implements Runnable {
public class ThreadTest extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("this is Thread");
    }
    public static void main(String[] args) {
        //使用Runnable的时候,其实Runnable是作为参数构造出一个thread对象的
        Thread runnablethread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this is Runable");
            }
        });
        runnablethread.start();
        Thread thread = new ThreadTest();
        thread.start();
    }
}


 无论是Tread和Runnable都有个缺点,线程执行完后不能返回结果,多线程数据交互一般都是直接存公共区,或者直接写到第三方存储,但有时候我们一些小的工具,不需要实现那么复杂,我只是用多线程做某个耗时的计算,异步获取结果而已。 这时候就需要Callable,Callable其实只是个接口,真正用的时候还需要配合future同时使用。


public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}


 Callable的定义也非常简单,只有一个call函数,和Runnable中的run不同的是,call是带返回值的。单纯Callable是不能被Thread执行的(因为Thread调用的是run函数),所以还需要Future, Future的get函数可以获取到call的返回值。


public class CallableTest{
    public static void main(String[] args) {
        Callable<String> callable = new Callable<String>() {
            public String call() throws Exception {
                return "Callable Test";
            }
        };
        FutureTask<String> futureFatask = new FutureTask<String>(callable);
        new Thread(futuretask).start();
        try {
            Thread.sleep(5000);
            System.out.println(futuretask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}


 上文说的Future怎么在代码里变成了FutureTask? 不是我代码写错了,因为在代码示例中我需要用Thread去启动线程,所以必须要有run函数才可以,虽然我没有显式实现run函数,但FutureTask里是有实现Runnable接口的。

 我们来看下FutureTask的定义。


public class FutureTask<V> implements RunnableFuture<V> {}

 FutureTask实现了RunnableFuture,再来看下RunnableFuture的定义。


public interface RunnableFuture<V> extends Runnable, Future<V> 

 RunnableFuture其实同时继承了Runnable和Future,所以FutureTask既可以当Runnable用,又能当Future用。FutureTask可以作为Thread的构造参数,但Future就不行了。这就是Future和FutureTask的区别。

 那Future在哪可以用呢? ExecutorService线程池,过两天再来一篇关于线程池的博客。

 在上面的demo中,当执行到new Thread(futuretask).start()的时候,后台就会新建一个线程异步去执行call函数,而不等call执行完,当前代码会继续执行下去。但是特别需要注意的一点是,当你用futuretask.get()来获取线程执行结果的时候,如果此刻call() 还没执行完,futuretask.get()会一直阻塞下去等待返回结果。

目录
相关文章
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
115 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
128 1
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
122 0
|
2月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
192 16
|
3月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
3月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
4月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
343 83
|
4月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
182 0
|
4月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
322 83

热门文章

最新文章