Java基础的线程概念

来源:互联网 发布:www.windows.com 编辑:程序博客网 时间:2024/05/16 05:29
// 每次执行JDK的java.exe程序,就启动了一个独立的java虚拟机进程,该进程的任务是解析并执行java程序代码
// 线程是指进程中的一个执行流程,一个进程可以有多个线程,分别执行不同的任务,当一个进程中的多个线程同时运行时,称为并发运行
// 许多服务器程序,如数据库服务器和Web服务器,都支持并发运行,这些服务器能同时响应来自不同客户的请求。
// 进程需要操作系统为其分配独立的内存地址空间,而同一进程中的所有线程在同一块地址空间中工作,这些线程可以共享同一块内存和系统资源
// 比如共享一个对象或者共享已经打开的一个文件。
// java虚拟机进程中,执行程序代码的任务是由线程来完成的,每个线程都有一个独立的程序计数器和方法调用栈
// 程序计数器:也称为PC寄存器,当线程执行一个方法时,程序计数器指向方法区中下一条要执行的字节码指令
// 方法调用栈:简称方法栈,用来跟踪线程运行中一系列的方法调用过程,栈中的元素称为栈帧,每当线程调用一个方法
// 的时候,就会向方法栈压入一个新栈,栈用来存储方法的参数,局部变量和运算过程中的临时数据。
// 栈帧的三个组成部分:局部变量区:存放局部变量和方法参数,操作数栈 :是线程的工作区,用来存放运算过程中生成的临时数据
// 栈数据区:为程序执行指令提供相关的信息,包括如何定位到位于堆区和方法区的特定数据,以及如何正常退出方法或者异常中断方法
// main方法为主线程,计算机中机器指令的真正执行者是CPU,线程必须获得CPU的使用权,才能执行一条指令,线程运行中需要使用计算机CPU和内存资源
// run()包含线程运行时所执行的代码,start()用于启动
// 1.主程序与用户自定义的程序并发运行
// 2.多个线程共享同一个对象的实例变量
// 3.不要随便覆盖Thread类的start()方法,假如一定要覆盖start()方法,那么应该先调用super.start()方法,确保线程被启动了,
// 4.一个线程只能被执行一次
// 线程的状态转换:
// 新建状态(New):用new语句创建的线程对象处于新建状态,在堆区中被分配了内存
// 就绪状态(Runnable):当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态
// java虚拟机会为它创建方法调用栈和程序计数器,处于这个状态的线程位于可运行池中,等待获得CPU的使用权
// 运行状态(Running):处于这个状态的线程占用CPU,执行程序代码,在并发运行环境中,如果计算机只有一个
// CPU,那么任何时刻只会有一个线程处于这个状态,如果计算机有多个CPU,那么同一时刻可以让几个线程占用
// 不同的CPU,使他们都处于运行状态,只有处于这种状态的线程才有机会转到运行状态。
// 阻塞状态(Blocked)阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行,当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新
// 进入就绪状态,才有机会转到运行状态:
// 阻塞状态分为3种:
// 1.位于对象等待池中的阻塞状态,当线程处于运行状态时,如果执行了某个对象的wait()方法,java虚拟机就会把线程放到这个对象的等待池中,
// 2.位于对象锁池中的阻塞状态,当线程处于运行状态,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,java虚拟机就会把
// 这个线程放到这个对象的锁池中,
// 3.其他阻塞状态:当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态
// 当一个线程执行system.out.println或者system.in.read方法时,就会发出一个I/O请求,该线程放弃CPU,进入阻塞状态,直到I/O处理完毕,该线程才会恢复运行
// 死亡状态(Dead):当线程退出run()方法时,就进入死亡状态,该线程结束生命周期,线程有可能是正常执行完run()方法退出,也有可能是遇到异常而退出,无论哪种都不会
// 对其他线程造成影响,
// Thread类的isAlive()方法判断一个线程是否活着,当线程处于死亡状态或者新建状态,该方法返回false,其余状态下,该方法返回true,
// 线程调度:为多个线程分配CPU的使用权,有两种调度模式:分时调度模型和抢占式调度模式
// 分时调度模式是指所有线程轮流获得CPU的使用权,并且平均分配每个线程占用CPU的时间片
// Java虚拟机采用抢占式调度模式,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中线程的优先级相同,那么就随机选择一个线程,使其占用CPU,
// 处于运行状态的线程会一直运行,知道他不得不放弃CPU,一个线程会因为以下原因放弃CPU.
// 1.java虚拟机让当前线程暂时放弃CPU,转到就绪状态,使其他线程获得运行机会。
// 2.当前线程因为某些原因而进入阻塞状态
// 3.线程运行结束
// 线程的调度不是跨平台的,它不仅取决于java虚拟机,还依赖于操作系统,在某些操作系统中,当前线程只要没有遇到阻塞,就不会放弃CPU,或者即使运行中的线程没有遇到阻塞,也会
// 在运行一段时间后放弃CPU,给其他线程运行的机会。
// 如果希望一个线程让另一个线程有运行的机会,可采用以下办法:
// 1.调整各个线程的优先级,2.让处于运行状态的线程调用Thread.sleep()方法,
// 3.让处于运行状态的线程调用Thread.yield()方法,4.让处于运行状态的线程调用另一个线程的join()方法
// 调整各个线程的优先级:优先级高机会越高,优先级低机会越低,Thread类的setPriority(int)和getPriority()方法分别用来设置
// 优先级和读取优先级,优先级用整数表示,取值范围是1-10,Thread类有以下3个静态变量:分别表示10,1,5
// 每个线程都有默认优先级,主线程的默认优先级为5,如果线程A创建了线程B,那么线程B将和线程A具有相同的优先级,当然,对于任意一个线程
// 都可以通过setPriority()方法来重新设置他的优先级
// 线程睡眠:Thread.sleep()方法,放弃CPU,转到阻塞状态,线程在睡眠时被中断,就会收到一个InterrupedException异常,线程跳到异常处理代码块
// 线程让步:Thread.yield()方法,当执行时,如果此时具有相同优先级的其他线程处于就绪状态,那么yield()方法将把当前运行的线程放到可运行池中并使
// 另一个线程运行,如果没有相同优先级的可运行线程,则yield()方法什么都不做
// sleep()方法和yield()方法区别:sleep不考虑优先级,yield只会给优先级相同或更高的程序一个运行的机会,前者进入阻塞状态,后者进入就绪状态
// sleep()和yield()用来提供程序的并发性能,yield一般在测试的时候用来提高程序的并发性能。
// join()等待其他线程结束,当前运行的线程可以调用另一个线程的join方法,当前运行的线程就转到阻塞状态,直到另一个线程运行结束,他才能恢复运行
// join(10),当前线程被阻塞的时间超过了10毫秒,或者那个线程运行结束时,主线程就会恢复运行。
// 获得当前线程对象的引用:Thread的currentThread静态方法返回当前线程对象的引用,
// 后台线程:指为其他线程提供服务的线程,也称为守护线程,java虚拟机的垃圾回收线程是典型的后台线程,负责回收其他线程不再使用的内存
// 后台线程特定:后台线程和前台线程相伴相随,只有所有前台线程都结束生命周期,后台线程才会结束生命周期,只要有一个前台线程没有结束运行,后台线程就不会结束生命周期
// 调用Thread类的setDeamon(true)方法,就能把一个线程设置为后台线程,Thread类的isDeamon()方法来判断一个线程是否是后台线程,
// 只要其他前台线程都运行结束,java虚拟机就会终止这个后台线程,只有在线程start开启前,才能把它设置为后台线程,如果在启动线程后再调用这个线程的setDeamon()方法,就会导致异常
// 默认前台创建的线程都是前台线程,由后台线程创建的线程在默认情况下仍然是后台线程
// 定时器Timer,它能够定时执行特定的任务,TimerTask类表示定时器执行的一项任务,TimerTask是一个抽象类,他实现了Runable接口,Timer(boolean isDeamon)允许把与Timer关联的线程设为后台线程 例如:Timer timer = new Timer(true);
// Timer本身不是线程类,但是他的实现中,利用线程来执行定时任务,Timer类schedual方法用来设置定时器需要定时执行的任务,task表示任务,depay表示延迟执行的时间,period参数表示每次执行任务的间隔时间  例如:timer.schedule(task,10,500)表示10毫秒以后开始执行task任务,以后每隔500毫秒重复执行一次task任务
// Timer类的schedule方法还有一个重载形式,使用他表明仅仅执行一次任务,以后不再重复执行,同一个定时器对象可以执行多个定时任务 例如:timer.schedule(task,10), 执行多个定时任务:timer.schedule(task1,0,1000), timer.schedule(task2,0,500)

// 线程的同步:为了保证正确的运算结果,一个线程在执行原子操作的期间,应该采用措施使得其他线程不能操纵共享资源,以生产者和消费者的例子来演示多个线程对共享资源的竞争

public class Test11 extends Thread {private int a;private static int count;public void start(){super.start();Thread deamon = new Thread(){@Overridepublic void run() {while (true) {reset();try {sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};deamon.setDaemon(true);deamon.start();}public void reset(){a=0;}public void run(){while(true){System.out.println(getName() + ":" + a++);if(count++==100){break;}yield();}}public static void main(String[] args) {Test11 t = new Test11();t.start();}}


0 0
原创粉丝点击