进程与线程进程是程序向操作系统申请资源(如内存空间、文件句柄等)的基本单位。线程是一个进程中可以独立执行的最小单元。JAVA线程API创建线程在Java中就是创建Thread类的一个实例。每个线程都有其要执行的任务。线程任务的处理逻辑是在Thread类的run方法中实现或调用的,所以run方法相当于线程任务逻辑处理的入口方法,由java虚拟机运行时对应的线程调用,而不是应用程序代码。Thread类的start方法用于启动相关的线程。启动线程的本质是请求java虚拟机运行相应的线程,线程何时运行由线程调度器决定。因此,虽然执行了start方法,但并不意味着线程开始运行,可能会稍后运行,也可能永远不会运行。Thread中常用的两个构造函数是:Thread()和Thread(Runnabletarget),这两个创建线程的方法如下:通过定义Thread类的子类来创建线程publicclassWelcomeApp{publicstaticvoidmain(String[]args){//创建一个线程ThreadwelcomeThread=newWelcomeThread();//启动一个线程welcomeThread.start();//输出“当前线程”的线程名System.out.printf("1.Welcome!I'm%s.%n",Thread.currentThread().getName());}}//定义Thread类SubclassofclassWelcomeThreadextendsThread{//在该方法中实现线程任务处理逻辑@Overridepublicvoidrun(){System.out.printf("2.Welcome!I'm%s.%n",线程.currentThread().getName());}}通过实现Runnable接口创建一个线程publicclassWelcomeApp1{publicstaticvoidmain(String[]args){//创建一个线程ThreadwelcomeThread=newThread(newWelcomeTask());//启动线程welcomeThread.start();//输出“当前线程”的线程名System.out.printf("1.Welcome!I'm%s.%n",Thread.c当前线程().getName());}}classWelcomeTaskimplementsRunnable{//在该方法中实现线程的任务处理逻辑@Overridepublicvoidrun(){//输出“当前线程”的线程名System.out.printf("2.欢迎光临!我是%s.%n",Thread.currentThread().getName());}}无论使用哪种方法运行,一旦线程的run方法执行结束,相应线程的运行就结束了,运行线程占用的资源会像其他java一样被java虚拟机垃圾回收对象。线程实例只能启动一次。如果多次调用实例的start(),将抛出IllegalThreadStateException。可以通过Thread.currentThread()获取当前线程,然后可以设置它的属性或者获取它的相关信息,例如:Thread.currentThread().setName("ThreadA");Thread.currentThread().getName();上面线程的run方法一般都是java虚拟机调用的,但是线程也是Thread类的一个实例。其次,run方法也被public修饰符修饰,所以也可以直接调用run方法,但一般不会这样,违背了我们床架线程的目的。publicclassWelcomeApp{publicstaticvoidmain(String[]args){//创建线程ThreadwelcomeThread=newWelcomeThread();//启动线程welcomeThread.start();//输出“当前线程”的线程名System.out.printf("1.Welcome!I'm%s.%n",Thread.currentThread().getName());welcomeThread.run();}}//定义Thread类的子类classWelcomeThreadextendsThread{//在该方法中实现线程任务处理逻辑@Overridepublicvoidrun(){System.out.printf("2.Welcome!我是%s.%n",Thread.currentThread().getName());}}===================结果====================1.欢迎您!我是主要的。2.欢迎!我是Thread-0.2。欢迎!我是main.threadattributeattribute属性typeandpurposeread-only重要说明numberID是用来标识不同线程的,不同的线程有不同的number是一定的,编号的线程运行结束后,这个number可能会被后续创建的线程使用.虽然不同的线程有不同的编号,但是这个编号的唯一性只对Java虚拟机运行一次有效。也就是说,Java虚拟机重启后(比如重启Web服务器),有的线程数可能和Java虚拟机上次运行的线程数一样,所以这个属性的值不适合用作唯一标识符,尤其是作为数据库中的唯一标识符(如主键)名称用于区分不同的线程。默认值与线程数有关。默认值的格式为:Thread-线程号,比如Thread-0NoJava没有禁止我们将不同线程的name属性设置为相同的值。但是设置线程的name属性,对于代码调试和问题定位是有帮助的。线程类别Daemon值为true表示对应的线程是守护线程,否则表示对应的线程是用户线程。该属性的默认值与对应线程的父线程的该属性值相同。java程序正常停止时,如果有用户线程还没有执行完,虚拟机不会立即停止,而是等待其执行完毕。但是,如果只是守护线程还没有执行完,并不会阻止虚拟机停止,也就是说守护线程通常用来执行一些不是很重要的任务,比如监控其他线程的状态线程。该属性必须在相应线程启动之前设置,即对于setDaemon方法的调用必须在调用start方法之前,否则setDaemon方法会抛出IllegalThreadStateException。负责一些关键任务处理的线程不适合设置为守护线程优先级Priority这个属性本质上是对线程调度器的一个提示,用于指示应用程序要先运行哪个线程。Java定义了从1到10的10个优先级,默认值一般为5。对于一个具体的线程,其优先级的默认值是否等于其父线程(创建该线程的线程)的优先级值一般使用默认优先级。该属性值设置不当可能导致严重问题(线程饥饿)threadmethodmethodfunction备注staticThreadcurrentThread()返回当前线程,即当前代码的执行线程(对象)Thread.currentThread()的调用通过同一段代码,它的返回值可能对应不同的线程(对象)。voidrun()用于实现线程的任务处理逻辑。该方法由Java虚拟机直接调用。一般情况下,应用程序不应调用该方法voidstart()启动相应的线程该方法的返回并不意味着相应的线程已经启动。Thread实例的start方法只能调用一次,多次调用会抛出异常。voidjoin()等待相应的线程完成运行。如果线程A调用了线程B的join方法,线程A的运行会被挂起,直到线程B运行完毕,staticvoidyield()使得当前线程主动放弃对处理器的占用,这可能导致当前线程要挂起的线程。这种方法是不可靠的。调用该方法时,当前线程可能还会继续运行(取决于系统当前的运行状态)。staticvoidsleep(longmillis)使当前线程休眠(暂停运行)一段指定的时间。Thread和Runnable的关系。Thread类实现了Runnable接口publicclassThreadimplementsRunnable{}Runnable是一个接口,里面只有一个方法,所以实现Runnable的类需要重新运行该方法。两种方式执行任务逻辑的过程实现了Runnable接口并重写了run方法;WelcomeTask实例在Thread中的调用过程中,会被赋值给Thread中的一个target成员变量privateRunnabletarget;具体过程如下:1、有一个参数constructor生成一个ThreadName,例如:Thread-0publicThread(Runnabletarget){init(null,target,"Thread-"+nextThreadNum(),0);}2.进入第一个初始化函数,不需要关注其他参数,因为还有其他构造方法会调用init(...)privatevoidinit(ThreadGroupg,Runnabletarget,Stringname,longstackSize){init(g,target,name,stackSize,null,true);}3.第二层初始化函数,将target赋值给privatevoidinit(ThreadGroupg,Runnabletarget,Stringname,longstackSize,AccessControlContextacc,booleaninheritThreadLocals){if(name==null){thrownewNullPointerException("namecannotbenull");}这个名字=名字;.....这。目标=目标;....}4.Thread实例调用start()方法publicsynchronizedvoidstart(){//threadStatus!=0表示这个Thread实例已经started(),所以如果(threadStatus!=0)thrownewIllegalThreadStateException()会抛出异常;...try{//最终会调用本地方法start0()启动线程start0();...}finally{...}}5.native方法启动线程,即把线程交给虚拟机的线程调度器privatenativevoidstart0();6.线程调度器执行线程任务逻辑//启动线程后,调度器会帮我们运行执行线程run()方法,即任务逻辑//如果target!=null,WelcomeTask中实现的任务逻辑会被调用,否则什么都不会执行publicvoidrun(){if(target!=null){target.run();}}继承Thread类,重写run方法classWelcomeThreadextendsThread{@Overridepublicvoidrun(){//任务逻辑}}newWelcomeThread().start();...//任务调度器直接调用WelcomeThread中实现的任务逻辑。两种方法的区别在于面向对象的角度:一种是基于继承来实现extendsThread,另一种是基于newThread(newRunable())的组合,组合比继承更不耦合。从对象共享的角度看:一个CountingTask实例可以被多个线程共享,所以可能存在资源竞争问题。类CountingThread扩展线程{intcount=0;@Overridepublicvoidrun(){for(inti=0;i<100;i++){i++;}}System.out.println("计数:"+计数);}classCountingTaskimplmentsRunnable{intcount=0;@Overridepublicvoidrun(){for(inti=0;i<100;i++){i++;}}System.out.println("count:"+count);}publicstaticvoidmain(String[]args){Thread线程;CountingTasktask=newCountingTask();for(inti=0;i<10;i++){thread=newThread(task);线程.开始();}for(inti=0;i<10;i++){thread=newCountingThread();thread.start();}}线程生命周期New(新创建的)Threadthread=newThread();当时线程只是准备new,并没有开始执行。Runnable(可运行)thread.start();1.ready:还没有分配资源。2.running:正在执行。阻塞1.Blocked(阻塞)没有获取到被synchronized保护的代码的锁。2.Waiting(等待)1.Object.wait();-o.notify()/o.notifyAll()2.Thread.join();-join线程结束/被中断Blocked和Waiting的区别在于Blocked是在等待某个资源被释放,Waiting是在等待某个条件被满足。TimeWaiting设置了一些阻塞时间参数。1.Thread.sleep(m);-超时/加入过程结束/被中断。2.Object.wait(m)-时间到了/o.notify()/o.notifyAll()3.Thread.join(m)-超时/加入过程结束/被中断。Terminated(终止)1.run方法正常执行。2.发生未捕获的异常并意外终止。
