java实现多线程的6种方式

多线程的实现方式主要有两种:一种是继承Thread,一种是实现Runnable接口,以下6种实际上是对这两种实现方式的一种变形:

1)继承Thread

2)实现Runnable接口

3)匿名内部类

4)定时器

5)基于Callable实现多线程

6)线程池

1.继承Thread

1)编写一个类MyThread继承Thread,重写run方法

2)新建MyThread的实例

3)调用start方法

package MultiThread.type1;

public class MyThread extends Thread {
    public MyThread(String name){
        this.setName(name);//此处的setName方法是调用父类即Thread类的方法
    }
    @Override
    public void run() {
        while(true){
            System.out.println("现在的线程是:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package MultiThread.type1;
//实现多线程的第一种方式,继承Thread
public class CreateThreadDemo1 {
    public static void main(String[] args) {
        new MyThread("hello").start();//此处使用MyThread的有参构造方法设置线程名称
        while(true){
            System.out.println("现在运行的线程是:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果

现在运行的线程是:main
现在的线程是:hello
现在运行的线程是:main
现在的线程是:hello

2.实现Runnable接口

1)创建一个类CreateThreadDemo2,实现Runnable接口,重写run方法

2)新建CreateThreadDemo2对象task

3)新建Thread对象,并指向对象task

4)调用start方法

package MultiThread.type2;
//实现多线程的第二种方式,实现Runnable接口
//相较于继承Trhead这种实现方式,这种方式可以降低耦合度
public class CreateThreadDemo2 implements Runnable{

    @Override
    public void run() {
        while(true){
            System.out.println("现在运行的线程是:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package MultiThread.type2;

public class MyThread2 {
    public static void main(String[] args) {
        //实例化线程任务类
        CreateThreadDemo2 task = new CreateThreadDemo2();
        //创建线程对象,将线程任务类作为构造方法的参数出入
        Thread t = new Thread(task);
        t.setName("hello");
        t.start();

        while(true){
            System.out.println("现在的线程是:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果

现在的线程是:main
现在运行的线程是:hello
现在的线程是:main
现在运行的线程是:hello

观察Runnable源码,发现这个接口只有一个未实现的方法,那么就可使用Lambda来简化代码的书写

:Lambda:JDK8的一个新特性。Lambda规定接口中只能有一个需要被实现的方法,而不是规定接口中只能有一个方法。语法形式为()->{},其中()为参数列表,->是Lambda运算符,{}是方法体,比如Runnable task=()->{//具体的功能},具体可参考Lambda表达式详解

package java.lang;

@FunctionalInterface
public interface Runnable {

    public abstract void run();

}

简化后的书写方式是:

package MultiThread.type2;
//使用Lambda简化书写,jdk1.8后有Lambda
public class Lambda {
    public static void main(String[] args) {
        Runnable task=()->{
            while(true){
                System.out.println("现在运行的线程是:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(task).start();

        while(true){
            System.out.println("现在的线程是:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

现在的线程是:main
现在运行的线程是:Thread-0
现在的线程是:main
现在运行的线程是:Thread-0

3.匿名内部类

其实这不是一种新的实现多线程的方式,只是一种写法。它又细化为继承Thread和实现Runnable两种方式。如果既既基于接口,又基于子类,经过测试,其实会基于子类运行

package MultiThread.type3;
//第3种方式,通过匿名内部类方式实现(它不是一种新的实现方式,只是一种写法)
//又细化为继承Thread以及实现Runnable
//如果既基于接口,又基于子类,那么其实会基于子类运行
public class AnonymosClass {
    public static void main(String[] args) {
        //1.继承Thread
        new Thread(){
            @Override
            public void run() {
                while(true) {
                    System.out.println("现在运行的线程是:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        //2.实现Runnable接口
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    System.out.println("现在运行的线程是:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        //3.既基于接口,又基于子类,那么其实会基于子类运行
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    System.out.println("现在运行的线程是基于接口的线程:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }){
            @Override
            public void run() {
                while(true) {
                    System.out.println("现在运行的线程是基于子类的线程:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        while(true){
            System.out.println("现在的线程是:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

运行结果

现在运行的线程是:Thread-0
现在运行的线程是:Thread-1
现在的线程是:main
现在运行的线程是基于子类的线程:Thread-2
现在的线程是:main
现在运行的线程是基于子类的线程:Thread-2
现在运行的线程是:Thread-1
现在运行的线程是:Thread-0

使用Lambda表达式改造匿名内部类方式中实现接口的形式,使代码更简洁:

package MultiThread.type3;
//使用Lambda改造匿名内部类中实现接口的形式,使代码更加简洁
public class Lambda {
    public static void main(String[] args) {
        //不适用Lambda
        new Thread(new Runnable() {
            @Override
            public void run() {
                //。。。
            }
        }).start();

        //使用Lambda:
        new Thread(()->{
            //。。。
        }).start();
    }
}

4.定时器

实现定时器的方式有多种,如JDK提供的Timer,Spring的schedule,quartz。这里用JDK提供的Timer类来实现定时器。

可以指定时间让定时器执行一次,也可间隔时间重复执行。

package MultiThread.type4;
//第4种实现多线程的方式,定时器
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerThread {
    private static final SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws ParseException {
        //1.指定时间
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("定时任务开始执行。。。");

            }
        },sdf.parse("2021-03-12 20:45:00"));//到达指定时间即运行一次

        //2.间隔时间重复执行
        Timer timer1=new Timer();
        timer1.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("定时任务2开始执行。。。");
            }
        },new Date(),1000);//每隔1秒运行一次
    }
}

运行结果

定时任务开始执行。。。
定时任务2开始执行。。。
定时任务2开始执行。。。
定时任务2开始执行。。。

5.基于Callable实现多线程

以上几种方式都有两个问题:1.无法抛出更多的异常;2.线程执行完毕之后不能拿到返回值。

Callable接口类似于Runnable接口,但比Runnable接口更强大,增加了异常和返回值

1)创建一个类实现Callable接口,实现call方法。
2)创建一个FutureTask,指向Callable对象,作为线程任务
3)创建线程,指定线程任务
4)启动线程

package MultiThread.type5;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//以上几种方式都有两个问题:1.无法抛出更多的异常;2.线程执行完毕之后不能拿到线程返回值。
//实现多线程的第5种方式,带返回值的线程实现方式,步骤:
//1.创建一个类实现Callable接口,实现call方法。这个接口类似于Runnable接口,但比Runnable接口更强大,增加了异常和返回值
//2.创建一个FutureTask,指向Callable对象,作为线程任务;
//3.创建线程,指定线程任务;
//4.启动线程。
public class CreateThreadDemo5 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Integer a=1;
        Callable<Integer> call=()->{
            System.out.println("异步线程任务开始");
            return 1;
        };
        FutureTask<Integer> task = new FutureTask<>(call);
        new Thread(task).start();

        //这里可以写一些别的代码

        Integer i = task.get();//拿到线程返回值
        System.out.println("主线程拿到异步线程返回结果:"+i);
    }
}

运行结果

异步线程任务开始
主线程拿到异步线程返回结果:1

6.线程池

package MultiThread.type6;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//实现多线程的第6种方式,线程池的方式。
public class CreateThreadDemo6 {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        while(true){
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程是:"+Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

运行结果

当前线程是:pool-1-thread-1
当前线程是:pool-1-thread-5
当前线程是:pool-1-thread-4
当前线程是:pool-1-thread-3
当前线程是:pool-1-thread-2
当前线程是:pool-1-thread-8
当前线程是:pool-1-thread-7
当前线程是:pool-1-thread-6
当前线程是:pool-1-thread-10
当前线程是:pool-1-thread-9

参考:实现多线程的几种方式

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值