线程的实现方式-简洁明了告诉你有几种,怎么做

作为一个开始学习进阶知识的小学生,并发编程是一个很重要的点,无论是以后面试,还是工作中都会用到,如果学会的话,可以让我们水平上一个台阶。

首先,我们需要知道,线程实现的方法。

public class RunnableThread implements Runnable{
    @Override
    public void run() {
        System.out.println("runnable接口实现");
    }
}

 

public class RunnableThread extends Thread{
    @Override
    public void run() {
        System.out.println("thread继承实现");
    }
}

 一般来说,我们有两种,一种是实现runnable接口,然后实现run()方法;另一种是继承thread接口重写run()方法。这两种方法应该说是最基础的回答。一般来说工作中经常用的也是这两种。

   记住 线程的实现方式就两种!!!千万不要说三种以上,因为其他的实现方式也都是基于这两种。可以说自己知道其他的用法,不可以说是实现方式!


 

   接下来讲一下,第三种,可以说做是创建线程的方法,线程池:

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

可以看到,线程池虽然很多个参数往里传,但是本质上还是通过一个new Thread来实现的 。

第四种,有返回值的callable创建线程,要和Future、FutureTask一起使用。

class CallableTask implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        return new Random().nextInt();
    }

}
public static void main(String[] args) {
        //创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        //提交任务,并用 Future提交返回结果
        Future<Integer> future = service.submit(new CallableTask());
    }

这种方式实际上是需要被执行的,而不是本身就是线程,只是说它们可以放到线程池中去运行,如代码所示,service.submit将方法放到线程池中,然后执行,实际上这种方式也是通过上述两种实现方式实现的(thread或runnable)。

还有一些比如定时器,匿名内部类,lamada表达式等,实际上都是一样的。

这时候,就会有小伙伴问,是不是说我之后只要说,所有线程的本质都是这两种方式咯,那我以后面试只要记住就可以了。

这我只能说,小伙子你还太天真了,真正最后的实现方式只有一种!构造Thread类。

首先我们看第一种实现Runnable接口的方式,启动线程要通过Thread.start()方法,然后start()还是会去调用run()方法,在run()方法里有一个target,这个target就是一个Runnable。

    /* What will be run. */
    private Runnable target;
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

这时候我们看一下第二种,继承Thread类,重写run()后,仍然是使用的Thread.start()方法,然后再调用run(),所以这个时候就明白,事实上创建线程只有一种方式,就是构造Thread类。

所以这两种方式到底有啥区别呢,都是通过构造Thread类进行创建的线程。

一个是通过实现run()的方式,实际上是一个Runnable的target去执行我们想要的方法,一个是通过重写run()的方式,执行的是run()里的我们想要的方法,从内存的角度来看,Runnable的线程池是创建好的,当我使用的时候,直接把任务放入线程池里,而继承Thread是每次都要自己创建一个线程空间来运行最后销毁,所以从这个角度来讲,Runnable比Thread效率要高一点。

 

最后说一下为什么事先Runnable要比继承Thread方法好。

1,java单继承,如果使用继承了,以后要使用这个类去继承别的不行,可扩展性不高。

2,上述提到的,Runnable的效率高一些。

3,Runnable只有一个run()方法,它定义了需要执行的内容,这种情况下,实现了Runnable和Thread的解耦,在Thread中是实现了Runnable接口的run()方法的。这样Thread类负责启动和属性设置,Runnable负责运行。

点击查看下一篇:如何正确停止线程,在使用volatile标记位的停止方法需要注意什么?

 

    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值