疯狂的多线程(1)

来源:互联网 发布:淘宝网店图片设计制作 编辑:程序博客网 时间:2024/04/29 20:46

        多线程,顾名思义,就是一个程序中多个线程几乎同时执行的一种技术。多线程是java特有的一种功能,重要性不言而喻。那有的同学就会问了,什么是线程?要想搞明白什么是线程,首先要搞明白一个概念:什么是进程。

      进程,字面理解的话可以理解为进行中的程序,进程是系统运行程序的基本单位,当我们打开任务管理器时,迎面而来的一大堆程序的名称就是所谓的进程。

     看上去进程是个很牛掰的东西,但是实际上进程只是用来分配该程序的内存空间,它并不是做事的人,那么,做事的是谁呢?

    做事的就是我们任劳任怨的线程,线程就是负责进程中程序执行的控制单元,也称为执行路径,实际上它就像是一条执行的路一样,所以进程中不可能没有线程。不要以为线程很神秘,实际上我们从接触java开始每天都和线程打交道,因为java中最最基本的main函数就是一个线程,叫做主线程,但是它本质上还是一条线程,假如说我们要执行下面的一段代码:

    如果我们想要等到输出“快运行我”,那我们就要等for循环的10000次结束之后才可以执行输出快运行我的语句,因为java在同一个线程中顺序执行,而main函数正是一个线程。

    但是,问题出现了,现在,我们需要在输出“线程你好牛掰啊”中间输出一个“快运行我”,这怎么搞,传统的顺序结构的程序必然无法解决这个问题。但是仔细想想,既然传统的main函数一个线程无法解决这个问题了,那么我们就再给他加一个线程吧,原来的一条执行路径无法解决的问题,那我们就再创建一条路径,一条执行for循环,一条执行输出“快运行我”不就完了吗。

    那有的同学就很开心啊,好啊,多条代码同时执行,多么高端,多么高效啊,干脆以后我什么程序都用多线程好了嘛,充分利用系统资源嘛,多线程看上去很美,但是实际上,多线程是有弊端的。很多同学都认为多线程是同时执行多条线程,但是请看看博客开头我对多线程的定义:几乎同时执行。什么叫几乎同时执行,几乎同时执行就是看起来像是同时执行,实际上并非同时执行的意思,要了解这个弊端,首先我们要先搞明白一个问题,cpu是如何运行程序的,当有多个程序正在运行的时候呢,比如说我一边用浏览器看视频,一边挂着QQ,cpu并不是说执行完看视频的任务再去执行挂QQ的任务实际上这也是不可能的,我们的cpu实际上执行的是一个随机切换的工作(不考虑优先级),可能说看视频的任务还没执行完就切换任务成了挂QQ的任务,这个切换的频率非常高,快到我们感觉他们是在同时执行的,但是实际上并不是我们可以通过一个例子直观感受一下,如果我们在解压一个很大的文件,本来预计3分钟可以打开的,但是如果我们打开了360的体检就会发现解压的预计时间可能变成了四分钟,因为等待cpu去执行的线程变多了,cpu随机到解压这个程序的概率变小了,所以解压所需要的时间变长了,所以,如果我们在程序中过多的使用多线程,就会导致程序运转效率变低,因此,我们要把多线程这个利器用在对的地方。

    说了那么多多线程的基本情况,优点缺点啊,那么多线程究竟该怎么用呢?实际上,java提供了这样一个类叫做Thread类供继承来实现多线程,下面,我们通过改造上面的程序来介绍如何使用多线程技术


我们新定义一个类并继承了Thread类,并重写了Thread类中的run方法,并在Main类中定义了Test对象,调用了test对象的start方法,输出结果如下

   果然实现了在输出“线程你好牛掰啊”之间输出“快运行我”的目的,那么,刚刚那段代码是什么意思呢,下面就着重来解决这个问题

   首先,我们可以在API文档中java.lang这个java文件的核心包里面查找到Thread这个类其中有这样几句话

  我们来分析一下上面几句话,第一句话是说如果想创建一个新的线程,那么可以将一个类声明为Thread类的子类,但是,只是继承不行,你还要重写Thread类的run()方法,为什么要重写呢,我们看看第二句话,第二句话的前半句我们可以不用理会,后文会有介绍,但是后半句很关键:当我们仅仅是继承了Thread类的时候,该类中的run()方法不执行任何操作并返回。这麻烦了,为什么呢?因为我们开启一个新的线程必然是要它能够执行一定的任务的,但是现在它居然不执行任何操作了,没关系,虽然它不执行任何操作,但是我们可以通过重写嘛,重写了run()方法,把你要在线程中实现的功能写在run()方法里面。写完了要调用吧,但是呢,你会发现调用run()方法呢,并没有实现多线程的目的,仅仅像是调用了一个函数一样,代码如下

我们再来看看运行之后的效果


我们可以发现,如果我们调用的是run()方法,实际上并没有开启多线程,仅仅像是调用了一个函数一样,程序中依然只有main()函数一个线程。为什么呢,我们继续回归前面的三行定义,java对于start()的定义是使线程开始执行,调用该线程的run方法,看到这里,我想原因已经很明确了,你继承了Thread类,重写了run方法只能算是做了准备工作,线程的开始执行的信号是start()函数给的,所以你必须要调用的是start()方法。至此,我们已经可以愉快的定义一个线程并且了解一些线程运行的基本内容了,但是,我们目前使用的方法是继承一个类,那么问题就来了,为了封装一个方法需要继承这一个类中的所有函数吗?java的单继承特点让我们无法同时继承两个类,如果我想让一个线程类继承一个类该怎么办呢?多线程除了会降低程序执行效率还有其他缺点吗?这些问题,我会在疯狂的多线程(2)中一一阐述,同样,这博客中也掺杂了一些我的个人观点,希望各位大神提出意见!谢谢。


0 0
原创粉丝点击