对于程序员来说,不管是Java还是其他开发语言,多线程编程是必不可少的,今天我们就先来了解一下Java多线程的实现方式,基本面试必考。

Java多线程实现有三种:

三种方式分别通过代码实例讲解:

1、继承Thread类

继承Thread并重写run()方法,Thread类中的start方法会去调用系统的方法执行相应的线程。实际上Thread也是实现了Runable接口的,如图:

java实现多线程编程 java多线程示例代码_d3

代码实例: 
package com.hadoop.ljs.learning.thread;/***功能描述 线程测试类 第一种方式 继承自Thread类* @author lujisen* @date* @param* @return*/public class MyThread extends  Thread{public static int sum=0;@Overridepublic void run(){while (true){//打印线程信息System.out.println("线程名称:"+Thread.currentThread().getName()+"当前sum值:"+(sum++));try {sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void  main(String[] args){/*创建三个线程*/MyThread thread1=new MyThread("线程1");MyThread thread2=new MyThread("线程2");MyThread thread3=new MyThread("线程3");thread1.start();thread2.start();thread3.start();}MyThread(String threadName) {Thread.currentThread().setName(threadName);}}2、实现Runable接口
实现Runable接口,并重写run()方法,启动线程必须要使用Thread类的start()方法,代码实例:
package com.hadoop.ljs.learning.thread;import static java.lang.Thread.sleep;/*继承Runnable接口*/public class MyThread2 implements Runnable{public static int sum=0;@Overridepublic void run(){while (true){//打印线程信息System.out.println("线程名称:"+Thread.currentThread().getName()+"当前sum值:"+(sum++));try {sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args){MyThread2 threadA=new MyThread2();Thread thread1=new Thread(threadA);thread1.setName("线程A");thread1.start();MyThread2 threadB=new MyThread2();Thread thread2=new Thread(threadB);thread2.setName("线程B");thread2.start();MyThread2 threadC=new MyThread2();Thread thread3=new Thread(threadC);thread3.setName("线程C");thread3.start();}}

3、实现Callable接口

上面的两个方式有两个问题,第一个是无法抛出更多的异常,第二个是线程执行完毕之后并无法获得线程的返回值。那么下面的这种实现方式就可以完成我们的需求; 从Java5开始就提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供一个call()方法作为线程执行体,call()方法可以有返回值,call()方法可以声明抛出异常,但是这种方式比较复杂,大体步骤如下:

1).创建一个类实现Callable接口,实现call方法。这个接口类似于Runnable接口,但比Runnable接口更加强大,增加了异常和返回值。

2).创建一个FutureTask,指定Callable对象,做为线程任务。

3).创建线程,指定线程任务。

代码实例:

package com.hadoop.ljs.learning.thread;import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;/*** @author: Created By lujisen* @company ChinaUnicom Software JiNan* @date: 2020-02-19 19:29* @version: v1.0* @description: com.hadoop.ljs.learning.thread*//*创建一个类实现Callable接口*/public class MyThreadCallable1  implements Callable{// 实现call方法。这个接口类似于Runnable接口,但比Runnable接口更加强大,增加了异常和返回值@Overridepublic Integer call() throws Exception{System.out.println("实现call函数开始业务逻辑....");Thread.sleep(5000);/*这里有返回值*/return 1;}public static void main(String[] args) throws Exception{// 创建一个FutureTask,指定Callable对象,做为线程任务。FutureTask task = new FutureTask<>(new MyThreadCallable1());// 启动线程new Thread(task).start();// 这里是在线程启动之后,结果返回之前,可干别的System.out.println("线程启动之后,可自定义业务逻辑,因为上面线程call函数中睡眠了5秒....");// 获取线程结果Integer result = task.get();System.out.println("主线程中异步任务执行的结果为:" + result);}}

三种方式区别:

第一种方式继承Thread就不能继承其他类了,后面两种可以;

使用后两种方式可以多个线程共享一个target;,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

获取和设置线程名称时,第一种既可使用this.setName()和this.getName()分别设置和获取当前线程名称也可使用Thread.currentThread().getName()和Thread.currentThread().setName(),而后两种必须要使用Thread.currentThread().getName()。

Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run();Callable的任务执行后可返回值,而Runnable的任务是不能返回值的;call方法可以抛出异常,run方法不可以;

运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。