Java创建多线程的方式

Posted 巧克力爱王子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java创建多线程的方式相关的知识,希望对你有一定的参考价值。

刚学了创建多线程的两种方式:继承Thread类、实现Runnable接口;

ps:下面又加了两种方式:实现Callable接口、线程池。

方式一:继承Thread类
1、创建一个继承于Thread类的子类;
2、重写Thread类的run()方法; 将此线程执行的操作声明在run()中
3、创建Thread类的子类对象;
4、通过此对象调用start()


//1、创建一个继承于Thread类的子类;
class MyThread extends Thread{
//  2、重写Thread类的run()方法; 将此线程执行的操作声明在run()中
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {//输出0~100中十的倍数
            if (i % 10 == 0){
                //Thread.currentThread().getName() 获得当前线程的名字
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class ThreadTest {

    public static void main(String[] args) {

//      3、创建Thread类的子类对象;
        MyThread myThread = new MyThread();

        //4、通过此对象调用start()( 1、启动当前线程;2、调用当前线程的run()方法)
        myThread.start();

//        主线程执行的操作
        for (int i = 0; i < 100; i++) {//输出0~100中十的倍数
            if (i % 10 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" +  i);
            }
        }

    }
}

 

方式二:实现Runnable接口
1,创建一个类实现Runnable接口
2、实现类去实现Runnable接口中的抽象方法run()
3、创建实现类的对象
4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5、通过Thread类的对象调用start()
 

//1,创建一个类实现Runnable接口
class MThread implements Runnable{

//    2、实现类去实现Runnable接口中的抽象方法run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 10 == 0){//输出0~100中十的倍数
                System.out.println(Thread.currentThread().getName() + ":" +i);
            }
        }
    }
}
public class ThreadTest1 {

    public static void main(String[] args) {
//       3、创建实现类的对象
        MThread mThread = new MThread();

//      4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
        Thread thread = new Thread(mThread);

//      5、通过Thread类的对象调用start()
        thread.start();

        for (int i = 0; i < 100; i++) {
            if (i % 10 == 0) {//输出0~100中十的倍数
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

比较创建线程的两种方式:
开发中:优先选择实现Runnable接口的方式
原因:1、实现的方式没有类的单继承性的局限性
2、实现的方式更适合来处理多个线程有共享数据的情况

 

方式三: 

1、创建实现Callable接口的类

2、重写call方法

3、创建Callable接口实现类的对象

4、将此Callable接口实现类的对象作为参数传递到FutureTask的构造器中,创建FutureTask对象

5、将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread类的对象,并调用start()方法

6、如果需要,获取Callable中call方法的返回值

//1、创建实现callable接口的类
class NumThread implements Callable{
    //2、重写call方法
    @Override
    public Object call() throws Exception {
        int sum = 0;

        for (int i = 0; i < 20; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}
public class ThreadTest3 {
    public static void main(String[] args) {
 //3、创建callable接口实现类的对象
        NumThread numThread = new NumThread();

 //4、将此callab接口实现类的对象作为参数传递到FutureTask的构造器中,创建FutureTask的对象
        FutureTask futureTask = new FutureTask(numThread);

//5、将FutureTask的对象作为参数传递到thread类的构造器中,创建Thread类的对象,并调用start方法
        new Thread(futureTask).start();

//6、获取callable中call方法的返回值
        try {
            Object sum = futureTask.get();
            System.out.println("总和为:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

 与使用Runnable相比, Callable功能更强大些:

1、相比run()方法,可以有返回值

2、方法可以抛出异常

3、支持泛型的返回值

4、需要借助FutureTask类,比如获取返回结果 

Future接口

可以对具体RunnableCallable任务的执行结果进行取消、查询是否完成、获取结果等。

FutrueTaskFutrue接口的唯一的实现类。

FutureTask 同时实现了Runnable, Future接口。它既可以作为 Runnable被线程执行,又可以作为

Future得到Callable的返回值

 

方式四:使用线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

解决思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频

繁创建销毁、实现重复利用。类似生活中的公共交通工具。

JDK 5.0 起提供了线程池相关 API ExecutorService Executors:
 
ExecutorService 真正的线程池接口。常见子类 ThreadPoolExecutor
 
void execute(Runnable command) 执行任务 / 命令,没有返回值,一般用来执行Runnable
 
<T> Future<T> submit(Callable<T> task) 执行任务,有返回值,一般又来执行Callable
 
void shutdown() 关闭连接池
 
Executors 工具类、线程池的工厂类,用于创建并返回不同类型的线程池
 
Executors.newCachedThreadPool() 创建一个可根据需要创建新线程的线程池
 
Executors.newFixedThreadPool(n); 创建一个可重用固定线程数的线程池
 
Executors.newSingleThreadExecutor() 创建一个只有一个线程的线程池
 
Executors.newScheduledThreadPool(n) 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行
//实现Runnable接口创建线程
class NumberThread implements Runnable{

    @Override
    public void run() {//重写run方法

        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0){

                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
//实现Callable接口创建线程
class NumberThread1 implements Callable{

    @Override
    public Object call() throws Exception {

        for (int i = 0; i < 20; i++) {
            if (i % 2 != 0){

                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
        return null;
    }
}
public class ThreadPool {
    public static void main(String[] args) {
        //创建一个10个固定线程数的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);

        //执行Runnable、Callable
        service.execute(new NumberThread());
        
        service.submit(new NumberThread1());

        //关闭连接池
        service.shutdown();
    }
}
好处:
 
提高响应速度(减少了创建新线程的时间)
 
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
 
便于线程管理

以上是关于Java创建多线程的方式的主要内容,如果未能解决你的问题,请参考以下文章

多线程创建方式

java-多线程创建

JAVA多线程

java 22 - 9 多线程之 代码实现的方式2

Java多线程-线程创建的3种方式

Java多线程——Lock&Condition