JAVA多线程的个人理解

来源:互联网 发布:orancle in优化 编辑:程序博客网 时间:2024/05/29 16:17

前几天初次接触到JAVA的多线程机制,是在网络编程的基础上学习了JAVA的多线程,在Socket长连接时,如果没有多线程,则只允许一个Socket接入,并执行内部的死循环操作,这和实际的通讯不符合,所以引入了多线程这一知识。

本以为多线程是需要语法来实现的,谁知JAVA给出了多线程的实现,是通过Thread类和Runnable接口来实现的。

Thread是通过新类(class Test extends Thread{run()})继承Thread,并重写内部的run方法来实现的,用start()方法开启多线程((new Test()).start())

Runnbale是一个未实现的接口,通过新类实现接口的run()方法(class Test implements Runnable{run()}),同样通过Thread的start()方法开启多线程(new Thread(new Test()).start())。

通过查API发现其实Thread也是Runnable的一个实现类,
这里写图片描述

虽然个人刚开始觉得Thread方法比Runnable方法方便的多,因为Runnable方法最后还是用到Thread,但是网上搜索后发现实际工作中还是使用Runnable方法多点,因为Runnable方法可以对实现一次new多次start来开启多线程,相当于多个线程对同一个对象操作,接口也突破了不能多继承的问题,所以在以后的使用中最好还是用Runnbale方法。相关的Thread和Runnable的区别与联系在网上有很多,这里可以看一下一篇简单明了的博客:
Java中继承thread类与实现Runnable接口的区别

作为小白,刚开始对多线程的理解就是多个任务同时进行,如同多个生产线同时工作,主线程就像给了一条命令给新线程,给了之后就继续自己的工作,再给下一条命令给又一个新线程,这些线程互不干扰在时间上是同步的。对多线程进行了如下的测试:

public class Thread_Test{    public static void main(String[] args){        for(int i=0; i<10; i++){            new Test_Thread().start();        }    }}class Test_Thread extends Thread{    public int i = 1;    public void run(){        System.out.println("线程:"+Thread.currentThread().getName());        System.out.println("线程:"+Thread.currentThread().getName()+"结果:"+(i++));    }}

得到结果:
结果

还可以多测几次,结果是不一致的,从结果可以看出线程的先后是随机的(可以看到线程0在后面,线程1在第一位,多次测试可能线程2在前面),run()里有两条输出,但在结果中两条输出不靠在一起;同时可以看出因为Thread方法需要多次new,所以输出的i值互不影响,都为初始值1。

这和我认为的不一致,因为之前我认为即使线程之间是同时运行的,但是外部还存在一个for循环,就像工厂里給命令是有先后一般,for循环启动了线程1,然后循环回来,才能再启动线程2,再循环回来,启动线程3,以此类推,所以他们之间总是有一个细微的由于for导致的时间差,得到的结果应该是线程1在整体上应该是先运行的,然而结果并不是如此,所以就来找找原因吧~

用API对Thread类进行查找,发现里面没有提到什么,只有概述和方法,对深入的内容没有补充,在网上找了很久没有找到想要的答案,要不就是太高深,要不就是具体的应用……
在论坛里看到一篇文章:
Java的多线程机制
发现里面很重要的一点就是“挂起”:

挂起: 线程挂起的原因有一下四种:
(1)、JVM将CPU资源从当前线程切换给其他线程,使本线程让出CPU的使用权,并处于挂起状态。
(2)、线程使用CPU资源期间,执行了sleep(int millsecond)方法,使当前线程进入休眠状态。sleep(int millsecond)方法是Thread类中的一个类方法,线程执行该方法就立刻让出CPU使用权,进入挂起状态。经过参数millsecond指定的毫秒数之后,该线程就重新进到线程队列中排队等待CPU资源,然后从中断处继续运行。
(3)、线程使用CPU资源期间,执行了wait()方法,使得当前线程进入等待状态。等待状态的线程不会主动进入线程队列等待CPU资源,必须由其他线程调用notify()方法通知它,才能让该线程从新进入到线程队列中排队等待CPU资源,以便从中断处继续运行。
(4)、线程使用CPU资源期间,执行某个操作进入阻塞状态,如执行读/写操作引起阻塞。进入阻塞状态时线程不能进入线程队列,只有引起阻塞的原因消除时,线程才能进入到线程队列排队等待CPU资源,以便从中断处继续运行。

简单来说,就是一条线程启动后,cpu说:“停下来,换人”,然后线程一就冻结了,接着线程二(或者三四五……)运行,接着任性的cpu又叫这个线程停下来,叫另一个线程工作(当然其实是线程抢占资源,而不是cpu主动去选择,选择哪个的过程由JVM决定)。
看完资料后觉得结果都想得通了,在此之前的一个盲点是,我没有把主线程(main)也想成和新建的线程是同一优先级的,主线程不是领导,而是在同一等级的流水线小工,还有一点就是其实大家不是同时工作的,对CPU的资源是要竞争的,对应到我的这个程序就是:

当程序运行到for循环,使用Thread开启了其他线程,到最后一共开启的了十个线程,加上主线程其实是11个线程。
线程之间是并发的,作用的时候每个线程都要抢占CPU资源,一个线程运行,其他线程就被挂起,被冻结,然后运行的线程运行时被挂起,其他线程中的一个运行……CPU反复切换,所以时间上只有一个线程在运行,只是CPU切换速度极快,导致看起来是多线程状态,主线程和新生成的线程优先级是一样,CPU的快速欺骗了我们。

对于测试的结果来说就是:main启动了线程1,线程1抢到了cpu资源,开心的工作了一下,并完成了输出,这时候main又抢了过来,在那么一瞬间启动了线程4,线程4昧着良心抢了main的资源开始开心的的工作,输出了一句话,又被main抢了过去,main生气的启动了线程5,线程5又抢了工作……在抢占cpu资源的过程中出现了这样的结果。

0 0
原创粉丝点击