多线程

来源:互联网 发布:电脑怎样下糖豆软件 编辑:程序博客网 时间:2024/06/16 06:10

多线程

         前言:多任务要求系统在同一时间执行多个任务,对于一个处理器,并不可能在同一时间运行多个任务程序,而是按照时间片在各个任务间快速切换执行来完成多任务要求的。这是基于实时操作系统RTOS的方法。

一:多线程的来源?

   答:随着操作系统的逐渐演变,网络技术的发展以及分布式应用的兴起,使得并发多任务机制越来越显得其重要性。我们已经很熟悉Windows,unix等操作系统中,多线程给我们带来了很大方便。

          操作系统把多任务的原理用到了程序的更低一层中发展成为多线程。

          因为空闲时间是公共的。网络的数据传输速率远低于计算机处理能力,多线程帮助你写出CPU最大利用率的高效程序,使得空闲时间保持最低。

二:什么是线程和进程?

           线程就是一条程序的执行线索,一行代码一行代码按时间一直向下执行,所执行的路线就是一条线程。如果这时还有另一个线程同时执行,也就是两个代码并行执行,这就是多线程。

 

       进程在本质上是一个执行的程序,是一个内核级的实体。

          它由程序控制块PCB(Process Control Block),程序,数据集合组成。

          它允许你同时运行两个或更多的程序。

       在基于线程的多任务处理环境中,线程是最小的执行单位。一个程序可以同时执行两个或者多个任务的功能。

       它们的区别是每个进程都有一组完整的属于自己的变量。而线程共享这些数据。

            和进程间的通信相比,线程间的通信要快得多。

 

       eg:打个比方,如果我们把银行看成是一个进程,则银行中的营业用具好比是进程表和变量,银行中的职员就好比是线程。如果银行只雇佣一个职员,就是进程概念,银行雇佣了多个职员,就好像进程中拥有多个线程,银行职员将共享银行中所有的营业用具。开辟营业点代价是昂贵的,但雇佣职员是很容易的。可见,进程与线程既有联系又有区别。

 

三:Java的多线程机制

     多线程的应用范围很广,它能对大量任务进行有序的管理,但在一般联系下,程序的一些部分同特定的事件或资源联系在一起,同时又不想为它而暂停程序其他部分的执行。这样一来,就可以考虑创建一个线程。令其与那个事件或资源关联到一起,并让它独立于主线程运行。

       eg:我们经常用quit按钮。比如我们从网上下载文件时,如果我们想中途中断时,我们便要考虑用另一个线程来编写quit按钮来及时退出,否则程序会专注于执行下载任务而不会理睬你的退出指令,一直等到当前任务完成。

 

四:线程的四中不同的状态

     New状态:线程对象被分配内存空间,私有数据被初始化。它只是放在内存中的程序。

     Runable状态:一旦调用start方法

     Blocked状态:三种情况:

                    ①:sleep(),wait(),suspend()方法任何其中之一调用

                    ②:线程调用只有在I/O完成时,才返回调用者的操作

                    ③:线程试图锁住已被另一个线程锁住的对象。

     Dead状态:当线程从自己的run方法返回后,或者调用stop方法都可以使线程处于Dead状态。

 

五:基于synchronized的同步机制

       Java语言从程序角度提供了各个线程间协调工作的调度能力,减低了并发程序设计的难度。但是多个线程共享数据而具有很多优点的同时,也带来了一些必须解决的问题。

        问题:假如两个线程共享同一个对象,且每一个线程都调用了能改变其状态的方法,因为线程中的很多数据共享相同的地址空间,这就导致了数据访问冲突以及数据前后不一致性。

       术语:在多线程程序中,将程序中那些不能被多个线程并发执行的数据或对象成为临界资源,Java用synchronized关键字来定义临时资源。

        eg: 银行取款转账问题:

                  当两个线程同时更新一个账户时,就会产生这类问题。

                 假设两个线程同时执行这条指令:item[to]+=amount;

                    事实上在执行这条指令时分解了一下步骤:

                        ①:装载item[to]到某个寄存器;

                        ②:将此寄存器的值加上amount;

                        ③:把寄存器的值存入item[to];

                如果第一个线程执行步骤①和步骤②后被中断,而第二个线程被唤醒并更新item[to]数组后,第一个线程接着执行步骤③。覆盖了第二个线程所做的工作,结果得不到正确的现金总额。

                  总之:一句话,因为线程中的很多数据共享相同的地址空间

             解决方法:

                Java提供了用synchronized修饰一个操作来解决共享数据的同步问题。例如:

                    public synchronized void bargain(int from ,int to ,int amount){      }

             解释:

                   当一个线程调用某个用synchronized修饰方法来访问这个对象时,这个线程就拥有了此对象的锁。另一个线程试图调用这个方法来访问此对象时,必须等到第一个线程退出这个被同步的方法放弃了对象锁。因此,这就保证了一个程序在没完成前不会被另一个线程中断,从而避免了上述例子中出现的问题。

           

六:创建线程的两种方式?

        创建线程的第一种方式:继承Thread类

           步骤:(1)定义类继承Thread

                      (2)覆写Thread类中的run方法

                      (3)调用线程的start方法,该方法两个作用:启动线程,调用run方法

        创建线程的第二种方式:实现Runnable接口

            步骤:1.定义类实现Runnable接口;

                       2.覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run方法中

                       3.通过Thread类建立线程对象;

                       4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。new Thread(t);

                       5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法

七:实现方式和继承方式有什么区别呢?(面试题经常考)

               实现方式好处:避免了单继承的局限性,

                  如果继承了一个类就不能再继承其他类了,在定义线程时,建议使用实现方式

               两种方式区别:

                  继承Thread线程代码存放Thread子类run方法中

                  实现Runnable,线程代码存放在接口的子类的run方

八:使用多线程机制会提高程序的运行效率吗?

               不会,因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行明确一点,在某个时刻,只能有一个程序在运行。(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果我们可以形象把多线程的运行行为在互相抢夺cpu的执行权这就是多线程的一个特性:随机性。即谁抢到谁执行,至于执行多长,cpu说的算。但是这样就好像是一个厨师在一个桌子上做馒头变成不停的换到别的桌子上做馒头,做的效率不会提高,而且性能还会更低。

九:为什么会有多线程下载?

            多线程运行效率并不会快,但是多线程会抢带宽,比如一个线程10k的下载,我们用20个线程就变成了200K,就是20个线程一起下载,这样就快啦。

 

十:传统线程互斥技术

 互斥:

         我们在使用多线程的时候,经常会遇到互斥问题,比如说两个同时运行的代码同时访问一个对象,两个线程都要取里面的数据,并对其进行修改,生活中最典型的例子就是银行账户,比如说一个商家的账户,他的客户给他汇钱的时候,他同时取这个账户里的钱,有可能在我们取钱的过程中,客户完成了汇款操作,这样我们就会从最开始的金额里减去我们取得钱,客户汇款的金额并没有加上,这样我们不就是要亏钱了嘛,这就是多线程中的互斥问题。我们肯定不能让这样的。

        线程安全问题可以用银行转账来解释。

 

多线程问题的原因

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就参与进来执行,导致共享数据的错误

解决办法

对多条操作共享数据的语句,只能让一个线程都执行完,在执行多次中,其他线程不可以参与执行

Java对于多线程的安全问题提供了专业的解决方法,这就是同步代码块

synchronized(对象)

{

      需要被同步的代码

}

哪些代码需要被同步,就看哪些语句操作共享数据。如果整个方法都需要被同步,那么就在这个方法中加上synchronized关键字。这里的对象可比作是锁,持有锁的线程可以在同步中执行没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁,这里的对象也可比作是火车上的卫生间

 

 

      

0 0
原创粉丝点击