JAVA线程(二)实现多线程的方式

Java多线程实现方式主要有四种:

1.继承Thread类 (没有返回值)
2.实现Runnable接口 (没有返回值)
3.实现Callable接口通过FutureTask包装器来创建Thread线程 (有返回值)
4.使用ExecutorService实现有返回结果的多线程。 (有返回值)

1.继承Thread类创建线程

Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程唯一的方法就是通过Thread类的start()实例方法。start()方法是一个native方法(native方法是用来调用计算机内部或其他语言的方法),它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
例如:

public class User extends Thread{

    private int i;

    public User(int i) {
        this.i = i;
    }

    @Override
    public void run() {
        System.out.println("User.run("+i+")");
    }

    public static void main(String[] args) {
        for(int i=1;i<100;i++){
            User user = new User(i);
            user.start();
        }
    }
}

2.实现Runnable接口创建线程

如果自己的类已经extends另一个类,因为java中的类是单继承,多实现的,无法直接extends Thread,此时,就可以实现一个Runnable接口,如下:

public class User implements Runnable{

    private int i;

    public User(int i) {
        this.i = i;
    }

    @Override
    public void run() {
        System.out.println("User.run("+i+")");
    }

    public static void main(String[] args) {
        for(int i=1;i<100;i++){
            User user = new User(i);
            Thread t = new Thread(user);
            t.start();
        }
    }
}

使用的时候实例化一个Thread,并传入自己的类实例,执行start()方法,与上文extends Thread同理。

3.实现Callable接口 - 有返回值

自己的类实现Callable接口,通过FutureTask包装器来创建Threa线程

public class User implements Callable {

    private int i;

    public User(int i) {
        this.i = i;
    }

	//重写的call()方法有返回值,可以通过FutureTask.get()来获取
    @Override
    public Object call() throws Exception {
        System.out.println("User.run("+i+")");
        return i;
    }

    public static void main(String[] args){
        List<FutureTask> ftList = new ArrayList<>();
        //先弄出来一堆线程
        for(int i=1;i<1000;i++){
            User user = new User(i);
            FutureTask ft = new FutureTask(user);
            Thread thread =new Thread(ft);
            thread.start();

            ftList.add(ft);
        }
        //调用get方法获取这一堆线程的返回值,注意:get方法是阻塞的(即:线程无返回结果,get方法会一直等待。)
        ftList.forEach(e->{
            try {
                System.out.println(e.get().toString());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
    }
}

4.使用ExecutorService

使用Executors类可以创建4种类型的线程池
1.Executors.newCachedThreadPool()
创建可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用),如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有60 秒钟未被使用的线程。
2.Executors.newFixedThreadPool(int nThreads)
创建固定长度的线程池。
3.Executors.newSingleThreadExecutor()
创建一个单线程的Executor。
4.Executors.newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行线程池,多数情况下可用来替代Timer类。

线程池常用启动方法有两个:

1.有返回值的:submit()方法
传递一个Callable,或Runnable,返回Future。
2.没有有返回值的:execute()方法
传递一个Runnable

无返回值的Code (实现Runnable,调用execute()方法)

//无返回值的Code
public class User implements Runnable {

    private int i;

    public User(int i) {
        this.i = i;
    }

    @Override
    public void run() {
    	//可以分别尝试四种线程池,打印线程的名称,来看到四种线程池的区别
        Thread thread = Thread.currentThread();
        System.out.println("User.run("+i+")" + "ThreadName:"+thread.getName());
    }


    public static void main(String[] args){

        ExecutorService service = Executors.newCachedThreadPool();
        //先弄出来一堆线程
        for(int i=1;i<100;i++){
            User user = new User(i);
            service.execute(user);
        }

    }
}

有返回值的Code,(实现Callable,调用submit()方法)

//有返回值的Code
public class User implements Callable {

    private int i;

    public User(int i) {
        this.i = i;
    }

    @Override
    public Object call() throws Exception {
        Thread thread = Thread.currentThread();
        System.out.println("User.run("+i+")" + "ThreadName:"+thread.getName());
        return i;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        ExecutorService service = Executors.newFixedThreadPool(20);
        //先弄出来一堆线程
        for(int i=1;i<100;i++){
            User user = new User(i);
            Future future = service.submit(user);
            //同理,get()方法是阻塞的
            System.out.println(future.get().toString());
        }

    }
}

备注:一般在项目中用线程池的话会被配成一个全局的,直接拿过来使用即可
springboot配置几个bean,使用的时候 @Resource注入进来即可。
点击这个跳转-项目线程池配置类

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值