遇到奇怪的多线程问题不要害怕。你可以看懂今天的文章😁。在最近的学习过程中,我遇到了这样一个问题:Java如何创建多线程?哪一种?你可能会说,没那么简单吧:好像继承Thread类实现Runnable接口一样。如果让我回答这个问题,我好像是这样回答的,顶多再回答一个callable的方式,但是啊,最近看到这样一个说法,让我陷入了深思。“在Java中创建多线程只有一种方式,那就是newThread的方式,嗯?这是怎么回事?这有点颠覆性,我不敢相信,所以这是怎么回事?”看到这个回答,我觉得我应该深入探讨一下这个问题。你一般是怎么问这个问题的?关于上面提到的问题,不是什么高深的问题,我们大多数人都能回答,但回答的可能不全面.我这里带大家找找,这个问题怎么出现在面试题中呢?这个问题让你回答,你会怎么回答,它说的是四种,哪四种?这里希望大家的重点应该是它怎么问的。这里说的是线程的实现方法。记住,是实现方法.让我们继续寻找其他面试问题:在这个version,这道题是这样问的,注意线程的创建,我们上面说的就是实现线程,没错,是另一种说法,但其实是一样的?如果在面试中被问到这样的问题,到底是问我们创建线程的方式还是线程的实现方式。我们的答案肯定是围绕继承Thread类和实现Runnable接口。相信没有多少人会上去说:创建线程的方法只有一种。一,就是newThread的方式。估计你的问题和答案肯定会被反问,为什么?是啊,为什么,其实看到这个回答之后,认真思考之后,我觉得这个说法并没有错。会不会是之前学的全错了,大家一起来分析一下。在Java中,有这样一个笑话,没有女朋友怎么办,那就换一个吧。学过Java的人都知道是怎么回事。在Java中,万物皆对象,创建对象一般是一种新的方式。在Java中,Thread是一个线程类。按理说我们创建一个thread对象,应该是newTread的方式。先来看看我们平时是怎么创建线程的。通常,我们建议实现接口。方法,是Java的单继承多实现派生出来的,我们一起来看代码:写完上面的代码之后,我们需要停下来思考下面的问题。我们在这里创建了一个线程吗?我们这里好像只创建了一个实现了Runnbale接口的类。好像没有地方反映我们创建了线程。来做个简单的测试:publicclassTest{publicstaticvoidmain(String[]args){//获取线程数ThreadGroupthreadGroup=Thread.currentThread().getThreadGroup();while(threadGroup.getParent()!=null){threadGroup=threadGroup.getParent();}inttotalThread=threadGroup.activeCount();System.out.println("Currentthreadcount:"+totalThread);}}我这里写了一个简单的程序,就是获取线程中有多少个线程当前默认的线程组,这段代码你不用管,你只需要知道它有什么用,我们运行一下试试:这里是6,然后我们把之前实现的Runnbale的类加入进去,我们拿一起看看:publicclassTest{publicstaticvoidmain(String[]args){//获取线程数ThreadGroupthreadGroup=Thread.currentThread().getThreadGroup();while(threadGroup.getParent()!=null){threadGroup=threadGroup.getParent();}inttotalThread=threadGroup.activeCount();System.out.println("当前线程数:"+totalThread);}}classMyThreadimplementsRunnable{@Overridepublicvoidrun(){System.out.println("Runnbale的实现方式...");}}main方法MyThread的体现,可想而知当前线程数还是6,我们一般怎么使用这个MyThread?是这样吗?publicclassTest{publicstaticvoidmain(String[]args){Threadthread=newThread(newMyThread());thread.start();//获取线程数ThreadGroupthreadGroup=Thread.currentThread().getThreadGroup();while(threadGroup.getParent()!=null){threadGroup=threadGroup.getParent();}inttotalThread=threadGroup.activeCount();System.out.println("当前线程数:"+totalThread);}}熟悉了,我们通常这样操作这个,在座的各位肯定都知道,真正启用线程需要调用start。我们再运行一??下看看:看,线程数增加了1,相关数据也打印出来了。这创建了一个线程,因为我们写了这样的代码:Threadthread=newThread(newMyThread());thread.start();foundNothing,重点来了,这里是newThread,我们接下来看这段代码:publicclassTest{publicstaticvoidmain(String[]args){newThread();//获取线程数.get线程组();while(threadGroup.getParent()!=null){threadGroup=threaddGroup.getParent();}inttotalThread=threadGroup.activeCount();System.out.println("当前线程数:"+totalThread);}}猜猜,当前线程数是多少?会不会有人说是7😂,你知道为什么吗,是因为你没有调用start,我们再看看:publicclassTest{publicstaticvoidmain(String[]args){newThread().start();1//获取线程数ThreadGroupthreadGroup=Thread.currentThread().getThreadGroup();while(threadGroup.getParent()!=null){threadGroup=threadGroup.getParent();}inttotalThread=threadGroup.activeCount();System.out.println("Currentthreadcount:"+totalThread);}}这个属于线程的基础知识。顺便说一句,你知道为什么调用start而不是run吗?上面解释的问题是什么?真正的线程创建还是通过newThread,然后调用start启动线程,看这个:Threadthread=newThread(newMyThread());thread.start();同样是newThread的方式,然后构造函数传入一个Runnbale,我们再看看Thread的构造函数:看,这里可以传入一个Runnable,我们继续思考为什么要创建线程?想想看。我们为什么要创建线程?简而言之,我们需要这个线程为我们工作吗?怎么做?简而言之,这是运行方法吗:@Overridepublicvoidrun(){System.out.println("ThewaytoimplementRunnbale...");}我们在这个运行方法中执行一些任务。其实Thread类中也有这个run方法。可以看一下:@Overridepublicvoidrun(){if(target!=null){target.run();}}Thread类中的run方法并没有具体执行某些任务,而是在target中执行run。这个目标是什么:privateRunnabletarget;是一个Runnbale,可以看看我们实现Runnbale的MyThread的类:=newThread(newMyThread());线程。开始();我想你应该明白了,这么大的一个圈就是执行MyThread中的run方法,因为这是我们新创建的线程会做的事情。可能之前我们真的错了,我们再看另一种长话短说,即继承Thread类的形式:classAextendsThread{@Overridepublicvoidrun(){System.out.println("继承Thread类的线程...");这个我们知道在Thread类中有这个run方法,上面已经给大家展示过了,所以这里要重写run方法,如果我们要启动这个线程,需要这样做:newA()。开始();这里newA的本质还是newThread,不用解释了,接下来我们再看看其他的方式,比如匿名内部类的方式:newThread(newRunnable(){@Overridepublicvoidrun(){System.out.println("匿名内部类创建线程的方式");}}).start();多么明显,还是new了一个Thread,然后继续看实现callable的方式:);返回1024;然后我们还需要这个:FutureTask
