线程各种方法的使用实例.doc_第1页
线程各种方法的使用实例.doc_第2页
线程各种方法的使用实例.doc_第3页
线程各种方法的使用实例.doc_第4页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

进程是程序的一次动态执行过程,它需要经历从代码加载,代码执行到执行完毕的一个完整过程。进程和线程一样都是实现并发的一个基本单位。线程是在进程的基础上进一步的划分,是比进程更小的执行单位。所谓多线程是指一个进程在执行的过程中可以产生多个更小的程序单元,这些单元被称作线程。这些线程可以同时存在同时运行。继承Thread类,必须重写run方法,该方法是线程主体,用于指定任务。启动线程要用start()方法(此方法里面有一个native声明的start0方法,表示调用本地操作系统函数。),使线程进入就绪状态,此时线程进入线程队列排队,等待cpu服务,此时具备运行能力。当就绪状态的线程被调用并获得处理器资源时,线程就进入运行状态,此时自动调用该线程的run方法。Runnable与Thread的关系类似与代理模式。Thread与我们自定义的线程类都实现了runnable接口,Thread类可以接受自定义类的实例对象,thread类并没有完全实现runnable接口中的run方法,它调用的是runnable接口的run方法,也就是runnable子类的run方法。1.为什么线程在启动时不能直接调用run()方法?因为线程的运行需要有本机操作系统的支持,Thread类中start()中定义了一个用native方法声明的start0()方法,表示调用本机的操作系统函数。虽然调用的是start()方法但还是执行的是run()方法的主体。Runnable类中没有定义start()方法,所以不能直接启动多线程。Thread类中定义了两个构造方法用于接受Runnable实例对象,依靠此点启动多线程:Public Thread(Runnable target), Public Thread(Runnable target,String name);Thread类中的run方法调用的是Runnable接口的run()方法(类似与代理模式,方法中有通过构造器接受的Runnable接口的实例,通过实例调用Runnable子类的run方法),所以如果通过继承Thread类实现多线程,则必须覆写run()方法,不然调用的就是Runnable接口子类的方法了。 直接调用run()方法实际上是main线程在执行。Java中所有线程都是同时启动的,那个线程抢到的cpu资源哪个线程就执行。Java运行时至少启动了main线程和垃圾回收线程。2.实现Runnable接口相对于继承Thread类来说,有如下优势:1. 适合多个相同程序代码的线程处理同一资源的情况。2. 可以避免java单继承性带来的局限。3. 代码能够被多个线程共享,代码与数据是独立的,增强了代码的健壮性。3.Runnable方式实现线程可以共享资源的原因因为一个线程只能启动一次,通过Thread实现线程时,线程和线程所要执行的任务是捆绑在一起的。也就使得一个任务只能启动一个线程,不同的线程执行的任务是不相同的,所以没有必要,也不能让两个线程共享彼此任务中的资源。 一个任务可以启动多个线程,通过Runnable方式实现的线程,实际是开辟一个线程组,将任务传递进去,由此线程组执行。可以实例化多个 Thread对象,将同一任务传递进去,也就是一个任务可以启动多个线程来执行它。这些线程执行的是同一个任务,所以他们的资源是共享。两种不同的线程实现方式本身就决定了其是否能进行资源共享。4.线程的状态:创建,就绪(调用start方法时),运行(获得CPU资源),阻塞,死亡。5.线程方法:String toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。 static void yield() 暂停当前正在执行的线程对象,并执行其他线程。static Thread currentThread() 返回对当前正在执行的线程对象的引用。 String getName() 返回该线程的名称。boolean isAlive() 测试线程是否处于活动状态。 void join() 强制执行。-等待该线程终止。void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 void setName(String name) 改变线程名称,使之与参数 name 相同。 void setPriority(int newPriority) 更改线程的优先级。 void getPriority() 获得线程的优先级。final void wait()线程等待。final void notify()唤醒第一个线程。Final void notifyAll()唤醒所有线程static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。static int activeCount() 返回当前线程的线程组中活动线程的数目。 void checkAccess() 判定当前运行的线程是否有权修改该线程。 long getId() 返回该线程的标识符。 int getPriority() 返回线程的优先级。 StackTraceElement getStackTrace() 返回一个表示该线程堆栈转储的堆栈跟踪元素数组。 Thread.State getState() 返回该线程的状态。 void interrupt() 中断线程。 static boolean interrupted() 测试当前线程是否已经中断。 boolean isDaemon() 测试该线程是否为守护线程。 boolean isInterrupted() 测试线程是否已经中断。 void join(long millis) 等待该线程终止的时间最长为 millis 毫秒。 void join(long millis, int nanos) 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 void stop() 已过时。 该方法具有固有的不安全性。Thread.suspend 和 Thread.resume?。 void stop(Throwable obj) 已过时。 该方法具有固有的不安全性。Thread.suspend void suspend() 已过时。 该方法已经遭到反对,因为它具有固有的死锁倾向。线程的操作:定义一个类继承runnable接口,重写run方法实现自己的逻辑。在另一个类的主方法中实例话该类的对象,然后定义线程对象(Thread类的构造器),线程对象调用start方法。6.同步与死锁同步: 一个多线程的程序如果是通过Runnable接口实现。则以为着类中的属性将被多个线程共享,就可能出现资源同步问题(卖票数为负数)可以通过加上synchronized代码块或者方法解决: Synchronized (this) Public synchronized void sale()死锁:同步可以保证资源共享的正确性,但是过多的同步就可能导致死锁的问题:两个同时执行同步的代码块中,都需要用到彼此的对象做锁。都会等对方释放对象,才能继续执行。就会出现死锁现象。一个死锁案例的结构:先定义两个类,都有相同的两个方法。定义一个多线程类,其中有私有的静态的前面两个类的饿汉式对象。一个标记变量。Run方法中利用标记变量if else 同步两个对象:分别利用两个对象同步一个对象的不同的方法,第一个方法后定义一个try-catch(InterruptedException e)语句块,Thread.sleep(500)。主方法中实例化两个多线程类的两个对象,设置两个对象的标记属性相反。然后实例化Thread类对象,调用start方法。7.线程的生命周期 Suspend()挂起,resume()恢复,stop()停止线程。这三种方法容易产生死锁问题。如果要停止一个线程的运行可以通过设置标志位的方式:在多线程类中定义一个布尔变量flag。在run方法中用while(this.flag)包起执行代码。再定义一个stop()this.flag=false;方法,当线程执行完时调用stop方法。8. 守护线程守护线程在没有用户线程可服务时自动离开,在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线程。这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务。将一个用户线程设置为守护线程的方式是在线程对象创建之前调用线程对象的setDaemon方法。典型的守护线程例子是JVM中的系统资源自动回收线程,我们所熟悉的Java垃圾回收线程就是一个典型的守护线程,当我们的程序中不再有任何运行中的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。那Java的守护线程是什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出。Java有两种Thread:“守护线程Daemon”与“用户线程User”。我们之前看到的例子都是用户,守护线程是一种“在后台提供通用性支持”的线程,它并不属于程序本体。任何线程都可以是“守护线程Daemon”或“用户线程User”。他们在几乎每个方面都是相同的,唯一的区别是判断虚拟机何时离开:用户线程:Java虚拟机在它所有非守护线程已经离开后自动离开。守护线程:守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去。setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为Daemon模式,false为User模式。setDaemon(boolean on)方法必须在线程启动之前调用,当线程正在运行时调用会产生异常。isDaemon方法将测试该线程是否为守护线程。值得一提的是,当你在一个守护线程中产生了其他线程,那么这些新产生的线程不用设置Daemon属性,都将是守护线程,用户线程同样。 这里有几点需要注意: (1) thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。 (2) 在Daemon线程中产生的新线程也是Daemon的。 (3) 不要认为所有的应用都可以分配给Daemon来进行服务,比如读写操作或者计算逻辑。 因为你不可能知道在所有的User完成之前,Daemon是否已经完成了预期的服务任务。一旦User退出了,可能大量数据还没有来得及读入或写出,计算任务也可能多次运行结果不一样。这对程序是毁灭性的。造成这个结果理由已经说过了:一旦所有User Thread离开了,虚拟机也就退出运行了。(把输入输出逻辑包装进守护线程多么的可怕,字符串并没有写入指定文件。原因也很简单,直到主线程完成,守护线程仍处于1秒的阻塞状态。这个时候主线程很快就运行完了,虚拟机退出,Daemon停止服务,输出操作自然失败了。)Sleep与Wait的区别:sleep(100L)是占用cpu,线程休眠100毫秒,其他进程不能再占用cpu资源,wait(100L)是进入等待池中等待,交出cpu等系统资源供其他进程使用,在这100毫秒中,该线程可以被其他线程notify,但不同的是其他在等待池中的线程不被notify不会出来,但这个线程在等待100毫秒后会自动进入就绪队列等待系统分配资源,换句话说,sleep(100

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论