多线程的应用:
1.网络聊天工具开发
一个线程负责发消息,一个负责收消息。两者互不干扰,如果是单线程,那么就可能前面在等待,而后面就接收不了消息。
2.大量数据库记录的复制。
如果一个复制要花3天时间,那么当你中途觉得没有必要,要停止的时候,你发现你不能让他停下来。而多线程的情况,一个
现成负责拷贝,是个无限循环
while(bStop)
{get data
copy data}
另一个现成监督是否有键盘按下,也就是把原本为true的变量bstop置为false。 bStop = false;当另一线程监视到变量 变化时会停止程序
3.www服务器为每一个来访者创建一个线程
一个线程必须处于如下四种可能的状态之一,这四种状态为:
初始态:一个线程调用了new方法之后,并在调用start方法之前的所处状态。在初始态中,可以调用start和stop方法。
Runnable:一旦线程调用了start 方法,线程就转到Runnable 状态,注意,如果线程处于Runnable状态,它也有可能不在运行,这是因为还有优先级和调度问题。
阻塞/ NonRunnable:线程处于阻塞/NonRunnable状态,这是由两种可能性造成的:要么是因挂起而暂停的,要么是由于某些原因而阻塞的,例如包括等待IO请求的完成。
退出:线程转到退出状态,这有两种可能性,要么是run方法执行结束,要么是调用了stop方法。
1.程序是计算机指令的集合,它以文件的形式存储在磁盘上。 进程:是一个程序在其自身的地址空间中的一次执行活动。 进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立的运行的单位,因此,它不占用系统的运行资源。 线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。 线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。 2.java对多线程的支持 java在语言级提供了对多线程程序设计的支持。 实现多线程程序的两种方式: (1)从Thread类继承; (2)实现Runnable接口。 例子: public class ThreadTest { /** } class MyThread extends Thread{ public void run(){ 打印的结果:main:main 为什么先执行 myThread.start()而打印的是main:main?因为程序开始调用的cpu将时间片分配给main函数,而此时开启另一个MyThread的线程时,cpu分配给main函数所在线程的时间片并未到期,故main函数执行完System.out.println("main:" + Thread.currentThread().getName())后,MyThread的线程才开始执行属于cpu分配给它的时间片。 后台线程: 当程序中只剩下后台线程时,java虚拟机就退出了。也就是说一个进程中没有非后台进程运行时,那么java虚拟机就要退出了。 当要设置线程为后台线程时,用Thread类中的setDaemon()方法,该方法必须在start()方法之前被调用。 2.线程暂停 Thread类中的yield()方法可以让当前线程暂停,转而让其他线程执行。 3.线程优先级 Thread类中的setPriority()和getPriority()方法可以设置和得到线程的优先级。 Thread类中的线程优先级有3种MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY,它们的类型为int,其值分别为10、1、5。设置优先级不一定要在start()方法前进行,可以随时修改线程的优先 级。在java中一个线程的优先级较高,它将始终获得执行的机会。 java是不支持线程时间片轮换的调度模型,而采用的是线程优先级高低的抢占调度模型。具有高优先级的线程可以抢占低优先级线程运行的机会。高优先级的线程将始终获得线程执行时间。但是这也不是绝对的,java线程调度器有可能会调用长期处于等待的线程进行执行,所以不要依靠线程的高优先级抢占模型去完成某些功能。 java线程调度器支持不同优先级线程的抢先方式,但其本身不支持相同优先级线程的时间片轮换。但是如果java运行时系统所在的操作系统(如windows2000)支持时间片的轮换,则线程调度器就支持相同优先级线程的时间片轮换。 4.用实现Runnable接口的方式调用线程 package com; public class MultiThread class MyThread implements Runnable 5.什么时候需要从Runnable接口实现run()方法,什么时候需要从Thread类去派生,来实现多线程? 通常情况下,我们并不需要去修改除了run()方法之外的其他方法的行为,最好都是去实现Runnable接口。它有两个好处: (1)当一个类继承了一个类后,当这个只能用实现Runnable接口的方式来产生线程类对象。 (2)当用实现Runnable接口的方式来产生线程类对象时,可以达到使多个线程类对象功用同一个变量的目的。 6. 线程的同步 同步的两种方式:同步块和同步方法 (1)对于同步块来说,我们需要在synchronized后加一个对象,这个对象是一个任意的对象。 (2)每一个对象都有一个监视器,或者叫做锁。 (3)同步方法利用的是this所代表的对象的锁。 (4)每个class也有一个锁,是这个class所对应的Class对象的锁。我们同步静态方法就是同步这个class所对应的Class对象的监视器。 7.线程的死锁 (1)哲学家进餐的问题 (2)线程1锁住了对象A的监视器,等待对象B的监视器,线程2锁住了对象B的监视器,等待对象A的监视器,就造成了死锁。 ●suspend和resume方法容易造成死锁,不建议使用。 8.wait、notify、notifyAll (1)每一个对象除了有一个锁之外,还有一个等待队列(wait set),当一个对象刚创建的时候,它的等待队列是空的。 (2)我们应该在当前线程锁住对象的锁后,去调用该对象的wait方法。(说明wait方法只能在同步块和同步方法中被调用。当调用wait方法的时候,我们这个线程就进入了这个对象的等待队列当中。) (3)当调用对象的notify方法时,将从该对象的等待队列中删除一个任意选择的线程,这个线程将再次成为可运行的线程。(notify方法只能在同步块和同步方法中被调用) (4)当调用对象的notifyAll方法时,将从该对象的等待队列中删除所有等待的线程,这些线程将成为可运行的线程。 (5)wait和notify主要用于producer-consumer这种关系中。 ●使用wait和notify方法时,必须是对同一个对象的等待队列进行操作。 9.线程的终止 (1)设置一个flag变量。 (2)结合interrupt()方法。 |