Java Thread
程序:是一段静态代码,它是应用软件执行的蓝本。
进程:是程序运行时的一个实例,对应了从代码加载、执行的一个完整过程,此过程也对应进程产生、发展到消亡的过程。
线程:比进程更小的执行单位,一个进程在其执行过程中,可以产生多个执行线程,即每个线程也有它的产生、发展到消亡的过程。是一个动态概念。
粒度层次不同,是两个不同层次上的概念。进程是由操作系统来管理的,而线程则是由进程来管理。
共享资源不同,不同进程的代码、内部数据和状态都是完全独立的,而一个进程内的多线程是共享进程空间资源的,有可能互相影响。
切换效率不同,线程本身的数据通常只有寄存器数据,以及一个进程执行时使用的堆栈,所以线程比进程切换负担小。
2.1 Thread 常用方法
Thread:
public static Thread currentThread( ):返回当前线程对象,是一个静态的方法。
public static void sleep( long millis):使当前线程进入睡眠状态,参数设定其等待时间,不会释放锁,静态方法。
public static void yield():使当前线程放弃执行,切换到其它线程,是一个静态方法。
Thread Instance:
public void start():启动线程,JVM将调用此线程的run方法,结果是将同时运行两个线程,当前线程和执行run方法的线程。
public void run():Thread的子类应该重写此方法,内容应为该线程应执行的任务。
public void stop():停止线程运行,并退出可执行状态。 【已过时】
public void resume():将暂停的线程继续执行。【已过时】
public void suspend():使线程暂停执行,不退出可执行态。【已过时】
public void interrupt():中断线程。
public void join():在当前线程中加入调用join方法的线程A,直到线程A死亡才能继续执行当前线程。
public void join(long millis):在当前线程中加入调用join方法的线程A,直到到达参数指定的毫秒数或线程A死亡才能继续执行当前线程。
public void setPriority(int newPriority):设置线程优先级。
public void setDaemon(boolean on):设置是否为后台线程。如果当前运行线程均为后台线程则JVM停止运行。该方法必须在start()方法之前使用。
public final void checkAccess():判断当前线程是否有权力修改调用此方法的线程。
public boolean isAlive():判断线程是否处于执行状态。返回值true表示处于运行状态,false表示已停止。
Object:
public void wait():在其他线程调用此对象的notify()方法或notifyAll() 方法前,使当前线程进入等待状态,会释放锁。
public void notify(): 唤醒在此对象监视器上等待的单个线程。
public void notifyAll():唤醒在此对象监视器上等待的所有线程。
2.2 main() 主线程与子线程
主线程:Java应用程序总是从主类的main()方法开始执行。当JVM加载代码,发现main方法之后,启动的线程称作“主线程”,该线程负责执行main方法。
子线程:在main方法的执行中再创建的线程。
如果main方法中又创建了子线程,那么JVM就要在主线程和子线程之间轮流切换,main方法即使执行完最后的语句,JVM也不会结束程序,JVM一直要等到程序中的所有线程都结束之后,才结束我们的Java应用程序。
2.3 Thread 线程创建两种方法
Thread类:Thread类的子类创建线程对象,子类重写Thread类中的run()方法;
在Java程序中创建多线程的方法之一是继承Thread类,从Thread类派生一个子类,并创建这个子类的对象,就可以产生一个新的线程。这个子类应该重写Thread类的run方法,在run方法中写入需要在新线程中执行的语句段。这个子类的对象需要调用start方法来启动,新线程等待CPU调度将自动进入run方法。当前线程将同时继续往下执行。
当创建子类的多个线程对象时,其成员变量和run()方法中局部变量都是互不干扰的。
Runnable接口:使用Thread类直接创建线程对象,但需要传入实现Runable接口的目标对象。
在编写复杂程序时相关的类可能已经继承了某个基类,而Java不支持多继承,在这种情况下,便需要通过实现Runnable接口来生成多线程。
使用Thread创建线程对象时,通常使用的构造方法是:Thread(Runnable target),该构造方法中的参数是一个Runnable类型的接口,因此,在创建线程对象时必须向构造方法的参数传递一个实现Runnable接口类的实例,该实例对象称作所创线程的目标对象。
当线程调用start方法后,一旦轮到它来享用CPU资源,目标对象就会自动调用接口中的run方法(接口回调)。
对于使用同一目标对象的线程,目标对象的成员变量自然就是这些线程的共享数据单元。不同run()方法中的局部变量互不干扰。
2.4 Thread 同步
synchronized -- 线程同步关键字
把需要修改数据的方法用关键字synchronized来修饰,用于指定需要同步的代码段或方法,也就是监视区。
当一个线程A使用一个synchronized修饰的方法时,其他线程想使用这个方法时就必须等待,直到线程A 使用完该方法 (除非线程A使用wait主动让出CUP资源)。
当被synchronized限定的代码段执行完,就释放对象锁(信号量)。
2.5 Thread 通信
为了更有效地协调不同线程的工作,需要在线程间建立沟通渠道,通过线程间的“对话”来解决线程间的同步问题。
java.lang.Object 类的一些方法为线程间的通讯提供了有效手段。
一个线程在使用的同步方法中时,可能根据问题的需要,必须使用wait() (挂起)方法使本线程等待,暂时让出CPU的使用权,并允许其它线程使用这个同步方法。其它线程如果在使用这个同步方法时如果不需要等待,那么它用完这个同步方法的同时,应当执行notify(), notifyAll()(恢复)方法通知所有的由于使用这个同步方法而处于等待的线程结束等待。
2.6 Thread 调度机制
每个Java线程都有一个优先级,其范围都在1和10之间。 默认情况下,每个线程的优先级都设置为5.
在线程A运行过程中创建的新的线程对象B,初始状态具有和线程A相同的优先级。可在线程创建之后的任何时候,通过setPriority(int priority)方法改变其原来的优先级。
基于线程优先级的线程调度:
具有较高优先级的线程比优先级较低的线程优先执行;
对具有相同优先级的线程,Java的处理是随机的;
底层操作系统支持的优先级可能要少于10个,这样会造成一些混乱。因此,只能将优先级作为一种很粗略的工具使用。最后的控制可以通过明智地使用yield()函数来完成;
假设某线程正在运行,则只有出现以下情况之一,才会使其暂停运行:
一个具有更高优先级的线程变为就绪状态(Ready);
由于输入/输出(或其他一些原因)、调用sleep、wait、yield方法使其发生阻塞;
对于支持时间分片的系统,时间片的时间期满;
通常,我们在一个线程内部插入yield()语句,这个方法会使正在运行的线程暂时放弃执行,这时具有同样优先级的线程就有机会获得调度开始运行,但较低优先级的线程仍将被忽略不参加调度;
2.7 Thread 挂起与恢复
挂起 有时候两个线程并不是同步的,即不涉及都需要调用一个同步方法,但线程也可能需要暂时的挂起。所谓挂起一个线程就是让线程暂时让出CPU的使用权限,暂时停止执行,但停止执行的持续时间不确定,因此不能使用sleep方法暂停线程。挂起一个线程需使用wait方法,即让准备挂起的线程调用 wait 方法,主动让出CPU的使用权限。
恢复 为了恢复该线程,其它线程在占有CUP资源期间,让挂起的线程的目标对象执行notifyAll()方法,使得挂起的线程继续执行;如果线程没有目标对象,为了恢复该线程,其它线程在占有CPU资源期间,让挂起的线程调用notifyAll()方法,使挂起的线程继续执行。
更多烟台编程相关资讯,请扫描下方二维码