Java 多线程

一、线程

1、程序:是一段静态的代码,它是应用软件执行的蓝本。

2、进程:是程序的一次动态执行过程,它对应了从代码的加载执行到执行完毕的一个完整过程。

3、线程:比进程更小的执行单位,一个进程在其执行过程中,可产生多个线程,形成多条执行线索,每条线索即每个线程,也有它自身的产生、存在与消亡的过程。

4、多线程编程的含义是:你可将程序的任务分成几个并行的子任务。特别是在网络中,你会发现很多功能是可以并发执行的。

5、多线程是与单线程相对而言的。

6、线程和进程的区别:

1)进程包括线程

2)进程都有一段专用的内存警戒(内存区域),子进程和父进程有不同的代码和数据空间。

3)多个线程共享数据空间,每个线程有自己的执行堆栈和程序计数器及执行上下文等。

4)多线程主要是为了节约CPU时间,提高效率。

7、新建的线程在它的一个完整的生命周期通常要经历5种状态:新建、就绪、运行、阻塞、死亡。

 

二、Sleep方法

1Thread类中有很多静态方法,这些方法都是在当前线程上运行的,即是在执行该方法的线程上运行的。

2、当线程处于空闲状态时,该线程必须将这个情况通知其他线程,以便其他线程有机会获得CPU控制权来运行自己的代码。

3Thread.sleep5);//5毫秒。;run方法中通过对sleep的调用表示该线程将在下面的5毫秒内处于空闲状态,5毫秒后它将再次启动运行(进入线程队列中排队)。

 

三、取得当前线程的名字和优先级

1、可通过调用Thread类的静态方法,查看当前运行的是哪一个线程。

2、获得当前线程的名字:

1currentThreadThread的静态方法,返回一个Thread的对象

    2getName

3、获得当前线程的优先级: Thread.currentThread().getPriority()setPriority();

4、判断当前正在占有CPU的那个线程:Thread.currentThread().线程的属性(与对象名比较)。

 

四、线程的属性

1、线程有四个属性

1new (新)创建状态: MyThread t = new MyThread( );或者Thread t = new MyThread();

2runnable(接口) :(可运行状态) t.start()

3blocked(被中断运行状态): sleep()wait()suspend()、其他阴塞。

4dead:死

1)自然撤消

2stop方法终止

2、新线程:当用new运算符创建一个线程时,该线程尚未运行,这意味着该线程处于“new”状态,此时程序尚未执行它里面的代码。在线程运行之前,需要进行一些程序管理操作。

3、可运行线程:一旦调用了start方法,该线程就启动成为一个可运行的线程。可运行的线程可以是尚未运行的线程。此时要由操作系统为该线程赋予运行时间。当线程内的代码开始执行时,该线程开始运行。

1)一旦线程开始运行,它不必始终保持运行状态。

2)正在运行的线程有时需要被中断,这样其他线程就有机会可以运行了。

3)线程调度的具体情况取决于操作系统提供的服务。

4)如操作系统不合作,那么java线程的实现机制要做少量的工作以便多线程能够运行。

5)在任何规定的时间上,可运行的线程可以运行,也可以不运行。

4、被中断运行的线程

1)下列操作之一,线程进入中断状态

A、调用线程的sleep方法。

B、线程调用了一个在输入、输出时中断的操作。即在输入和输出操作完成之前,该操作不会返回到它的调用程序。

C、线程调用wait方法。

D、线程试图锁定一个当前被另一个线程锁定的对象。

E、调用线程的suspend方法(此方法已作废)。

2)当一个线程被中断,可以安排另一个线程运行。

3)已中断的线程重新激活时,调度程序要查看该线程的优先级是否高于当前运行的线程。

5、退出中断状态:(与进入中断相反)

1)如线程已置于睡眠(sleep)状态,须经过规定的毫秒数

2)如线程正在进行一个输入/输出操作,须等待该操作执行完毕。

3)如线程调用了wait方法,则另一个线程必须调用notifynotifyAll

4)如线程正等待另一个线程拥有的对象锁,那么另一个线程必须放弃该锁的控制权(所有权)。

5)如线程已暂停运行(调用suspend方法),必须有人调用resume方法(已作废)。

6)如调用一个与线程上的状态不一致的方法,虚拟机会抛出一个IllegalThreadStateException异常。

6、死线程

1run方法的正常退出而自然死亡。

2)没有抓取到的异常事件终止了run方法的执行,而导致线程突然死亡。

3)特定情况下,可通过线程的stop 方法杀死线程。该方法将抛出一个ThreadDeath出错对象,从而杀死线程(已作废)。

7、判断当前线程是否存活:isAlive()

1)如是可运行或被中断,返回ture

2)如是新线程或尚未成为可运行线程,或是个死线程,返回false

 

                                        sleep←→到时间

新线程→→启动→→可运行|-----------------------------------------|被中断

                  ∣ ↑                I/O操作→完成                 ↑

                  ∣ ∣-------------------------------------------------∣

                   ∣ ↑            wait←notify/notifyAll            ↑

                  ∣ ∣-------------------------------------------------∣

                   ∣ ↑                等待锁定→锁定                 ↑

                  ∣ ∣-------------------------------------------------∣

                   ∣ ↑              挂起suspend←resume              ↑

                  ∣ ∣…………………………………………………………………∣

                   ∣                        正常退出            

                  ∣--------------------------------------------------→死

                   ∣                          stop                      ↑

                  ∣……………………………………………………………………∣

 

五、实现线程的两种方式:

1、继承Thread类。

2、实现Runnable接口。

 

六、显示定义线程

public Thread(ThreadGroup group,Runnable target,String name)

其中:第一个参数:线程组。

      第二个参数:是执行线程体(run)的目标对象,该对象必须实现Runnable接口。

      第三个参数:线程名。

 

七、启动和运行线程

1、程序启动时总是调用main方法,因此,mani方法是创建和启动线程的地方。

  MyThread t=new MyThread();  //创建

  t.start();  //运行,真正启动了一个线程。

2、构造一个新的线程,此线程从Thread类派生而来。产生对象时,并不会执行其中的run方法。

3、新线程只能由start方法启动,然后该线程才能自动执行run方法。即start()执行后自动调用run()

 

八、启动接口

1、当我们构造了线程类的一个新的实例,我们必须先告诉它在新的线程里应执行哪一段程序,我们可以在任意实现了启动接口的对象上启动一个线程。

2、启动接口是一个抽象接口,表示本对象中有一个方法想异步执行。

3Runnalbe接口中只定义了一个方法run作为线程体。

 

九、线程的优先级

1、在java语言中,每个线程都有一个优先级。

2、在默认条件下,一个线程将继承其父线程的优先级。

3、可以用setPriority方法来提高或降低线程的优先级。

4、可以设置线程的优先级:

1)最小MIX_PRIORITY1);

2)最大MAX_PRIORITY10);

3)默认NORM_PRIORITY5);

5、当线程调度程序有机会选择一个新线程时,它通常会选择当前运行的高优先级线程。

6、注意:线程优先级的使用原则是与系统有密切关系的。当虚拟机取决于主机平台的线程机制时,线程的调度完全要受线程机制的支配。虚拟机将线程优先级映射为主机平台优先级等级(主机平台的线程优先等级可能要更多或更少一些)。我们在学习过程中只是一种理想情况,每个虚拟机都可以设法在某种程度上接近这种理想的情况。

7、最高优先级的可运行线程将始终保持运行状态,直到:

1)它通过调用yield方法放弃运行为止。

2)或它不再是个可运行线程(原因是它已经死掉,或进入中断状态)。

3)或一个高优先级线程已经变成可运行线程(原因是该高优先级线程已经睡眠了足够长的时间或它的I/O操作已经完成,或有人调用了该线程正在等待的对象上的notify/notifyAll方法)。

4)此时,调用程序便选择一个新线程来运行。在可运行线程中拥有高优先级的线程将会被选中。

8、如果有多个可运行的线程,同时拥有相同的(最高)优先级,则拥有最高优先级的多个线程中的一个将被选中运行。

9、这完全取决于线程高度程序对拥有多个相同优先级的线程的仲裁。

10java语言不能保证所有线程能得到一视同仁。

11、拥有相同优先级的所有线程可能都希望依次被选中,以便使每个线程的运行都有机会取得进展。但,至少理论上讲,在某些平台上线程调度程序将会随机选择一个线程,或始终选择第一个可等到的线程。这是java语言的一个弱点,并且很难编写能够保证在所有虚拟机上以相同的方式运行多线程程序。

12、警告:有些平台(如winNT)的优先级少于java平台指定的10个级别。在这些平台上,无论选择何种优先等级的映射关系,java虚拟机的10个优先级等中的某些层次将被映射为相同的平台优先级等级。在sun 公司的LinuX java虚拟机中,线程的优先级被完全忽略。

13yield方法:用于使当前正在执行的线程放弃执行。如果有其它要运行线程的优先级至少与该线程的优先级相同时,那么它们将被安排在下次运行。注意,这是一个静态方法。

14、利己线程:当某个线程正在执行一个很长的循环时,它应该始终调用sleepyield方法,以确保它不会独占整个系统。不遵循这个原则的线程称为利己线程。

 

十、守护线程 Daemon

1、说明:

1)守护线程是一个简单的背景线程,隶属于创建它的线程,因此当创建守护线程的线程结束,守护线程也随之一起结束。

2)不是守护线程的线程叫用户线程。用户线程有它自己的生命周期,不依赖创建它的线程。当创建它的线程结束后,它可以继续执行。

3)守护线程有时也叫服务线程,它为同一个进程中的其他线程或对象提供服务,通常在一个较低的优先级上运行。如:垃圾回收线程。除此之外,它没有其他特别的功能。如果剩下的线程都是守护线程,就没有必要使程序保持运行状态,该程序便会退出运行。

    2、例:

一个网络服务器可以由一个用户线程全面管理,该用户线程启动一个或多个监听请求的守护线程。当服务器启动时,操作员启动管理线程并且由这个线程创建守护线程监听请求。守护线程将监听到的任何可以识别的请求,交由另一个由监听线程创建的线程处理,所以每个请求被独立地处理。处理事务花费有限多时间,在系统关闭前,请求被满足很重要。处理请求的线程应该是一个用户线程,以确保即使创建它的线程结束,它仍可继续运行来完成事务处理。当关闭系统时,操作员不必担心有多少线程正在运行。当主要线程关闭时,所有的监听线程也将关闭,因为它们是守护线程。然后任何处理特定事务未完成线程运行到完成。

3、使用:

1t.setDaemon(true);通过此方法可以把线程变成一个守护线程(如果为false,则为用户线程)。

2)本方法必须在线程启动运行之前调用。如在后来调用,这个方法将抛出一个IllegalThreadStateException异常。

3)由一个守护线程创建的线程默认情况也将是守护线程。

 

十一、线程组:flashget中的一个下载,同时开的线程数

1、说明

1)有些程序包含了相当数量的线程,这时按照线程的功能将它们分成不同的类别将很有用。

2)每个线程都是一个线程组的一个成员,线程组把多个线程集成一个对象,通过线程组可以同时对其中的多个线程进行操作。

3)在生成线程时,必须将线程放在指定的线程组中,也可以放在缺省的线程组中,缺省的就是生成该线程的线程所在的线程组。一旦一个线程加入某个线程组,就不能被移出这个组。

4java应用程序开始运行时,系统将生成一个名为main的线程组,但对于applet不同的浏览器会生成不同名字的线程组。

2、使用:

1)创建组

String groupName="group";

ThreadGroup g= new ThreadGroup(groupName);

2ThreadGroup构造函数的字符串参数用于标识该线程组,并且它必须是独一无二的。

3)然后,将各个线程添加到组中,方法是在构造线程时设定组。

Thread t = new Thread(g,"threadName");

4)取得现有线程的线程组:

ThreadGroup group=myThread.getTreadGroup( );

5)取得现有线程的父线程组

ThreadGroup parentGroup=group.getParent( );

6)若要确定某个线程组中的任何一个线程是否仍处于可运行状态,可使用activeCount方法。

if (g.activeCount()==0){//组中所有线程已经停止}

7)若要中断某个线程组中所有线程的运行,只需在线程组对象上调用interrupt方法:

        g.interrupt();

 

十二、同步

    1、说明:

        1)因为多线程给你提供了程序的异步执行的功能,所以在必要时必须还提供一种同步机制。

    例如,你想两个线程通讯并共享一个复杂的数据结构,你需要一种机制让他们相互牵制并

    正确执行。为这个目的,Java用一种叫监视器(monitor)的机制实现了进程间的异步执行。

    可以将监视器看作是一个很小的盒子,它只能容纳一个线程。一旦一个线程进入一个监视器

    ,所有其他线程必须等到第一个线程退出监视器后才能进入。象一把锁,每个对象和一个监视器

    对应,如果不全使用同步方法,监视器不起作用。

        2)这种监视器可以设计成保护共享的数据不被多个线程同时操作。大多数多线程系统将这种

    监视器设计成对象,Java提供了一种更清晰的解决方案。

        3)没有Monitor类:每个对象通过将他们的成员函数定义成synchronized来定义自己的监视

    器,一旦一个线程执行在一个synchronized函数里,其他任何线程都不能调用同一个对象

    synchronized函数。

2、争用条件(race condtion)大多数实际运行的多线程程序中,两个或多个线程需要共享对同一个对象的访问。如两线程访问同一对象,并且每个线程都调用一个方法,以便修改对象的状态。根据数据被访问的顺序将会产生损坏对象的情况,这种情况,通常叫作争用条件。

3、对象锁

1)当线程调用Synchronized方法时对象将转为锁定状态。

2)线程调度程序会定期使用正常的激活规则,对等待开锁的线程进行激活。

3)每当一个想要调用对象上的Synchronized(关键字)方法的线程想再次运行时,它想看该对象是否仍处于锁状态。

4)如该对象的锁已经打开,那么该线程便是下一个获得对该对象的唯一访问权限的线程。

4、等待与通知:

1wait

A、当Synehronized方法中的wait方法被调用时,当前线程将被中断运行,并且放弃该对象的锁,这可以使另一个线程启动。

BwaitObject类的方法,而不是Thread类的方法。

C、一旦线程调用了wait方法,它便进入该对象的等待列表中,被删除之前,调度程序将忽略该线程,并且该线程没有机会继续运行。

2notify/notifyAll

A、调用这两个方法,从等待列表中删除线程。

B、删除后,再次成为可运行的线程,且调度程序最终会重新激活它们。

C、然后它们试图重新进入该对象,一旦可以使用该对象锁定时,其中的一个线程将锁定该对象,且从它上次调用wait方法后的位置开始继续执行。

3)其他线程必须定期调用notify/notifyAll。这一点很重要。

4)当一个线程调用wait方法时,它不能开自己的锁,只能靠其他线程来帮它开锁。如果没有其他线程来开锁,它将永不能运行。这就产生死锁。

5、消息

     一旦你的程序被分成几个逻辑线程,你必须清晰的知道这些线程之间怎样相互通讯。java提供了waitnotify等功能来使线程之间相互交谈。一个线程可以进入某一个对象的synchronized函数进入等待状态,直到其他线程显式地将它唤醒。可以有多个线程进入同一个方法并等待同一个唤醒消息。

 

十三、小结

1、多线程是java语言的重要特点,java语言用Thread类封装了线程所有操作

2、线程的接口为Runnable

3、实现线程的两种方式

1)继承Thread

2)实现Runnable接口

4、线程之间的同步机制为Synchronized(象static一样也是关键字)

5、线程之间的通信靠wait.notify

 

常用API

1、静态方法:currentThread(),该方法返回当前正在运行的线程的对象

           yield停止当前线程

           sleep睡眠指定时间

2、实例方法

start,run,stop,suspend,resume,setPrioity,setName,getPriority,getName

3interrupt()//线程调用,消灭本线程,在线程执行完前。

4、在线程执行完run方法之前,重新执行start()方法时产生IllegalThreadStateException异常。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值