2024年10月java多线程机制(什么是Java多线程编程)

 更新时间:2024-10-12

  ⑴java多线程机制(什么是Java多线程编程

  ⑵什么是Java多线程编程

  ⑶我们现在所使用操作系统都是多任务操作系统(早期使用的DOS操作系统为单任务操作系统),多任务操作指在同一时刻可以同时做多件事(可以同时执行多个程序)。

  ⑷Java中实现多线程的方式:

  ⑸当我们自定义的类继承Thread类后,该类就为一个线程类,该类为一个独立的执行单元,线程代码必须编写在run()方法中,run方法是由Thread类定义,我们自己写的线程类必须重写run方法。

  ⑹run方法中定义的代码为线程代码,但run方法不能直接调用,如果直接调用并没有开启新的线程而是将run方法交给调用的线程执行

  ⑺要开启新的线程需要调用Thread类的start()方法,该方法自动开启一个新的线程并自动执行run方法中的内容

  ⑻java多线程的启动顺序不一定是线程执行的顺序,各个线程之间是抢占CPU资源执行的,所有有可能出现与启动顺序不一致的情况。

  ⑼如何使用CPU资源是由操作系统来决定的,但操作系统只能决定CPU的使用策略不能控制实际获得CPU执行权的程序。

  ⑽线程执行有两种方式:

  ⑾目前PC机中使用最多的一种方式,线程抢占CPU的执行权,当一个线程抢到CPU的资源后并不是一直执行到此线程执行结束,而是执行一个时间片后让出CPU资源,此时同其他线程再次抢占CPU资源获得执行权。

  ⑿每个线程执行固定的时间片后让出CPU资源,以此循环执行每个线程执行相同的时间片后让出CPU资源交给下一个线程执行。

  ⒀希望对您有所帮助!~

  ⒁JAVA线程的机制有哪些

  ⒂Java的线程机制摘要:多线程机制是Java的重要技术,阐述了线程和进程的差别;Java中线程个状态之间的转换;并结合例子说明了两种创建线程的方法。线程是指程序中能顺序执行的一个序列。一个线程只有一个入口点?但可能有几个出口点?不过,每个时刻的执行点总是只有一个。线程是不能独立运行的程序,而只是某个整体程序内部的一个顺序执行流。多线程是Java的一个重要特点。如果一个程序是单线程的,那么,任何时刻都只有一个执行点。这种单线程执行方法使系统运行效率低,而且,由于必须依靠中断来处理输入/输出。所以,当出现频繁输入/输出或者有优先级较低的中断请求时,实时性就变得很差。多线程系统可以避免这个缺点。所谓多线程,就是通过系统的调度使几个具有不同功能的程序流即线程同时并行地运行。在单处理器计算机系统中,实际上是不可能使多个线程真正并行运行的,而要通过系统用极短的时间、极快的速度对多个线程进行切换,宏观上形成多个线程并发执行的效果。1线程和进程机制上的差别线程和进程很相象,它们都是程序的一个顺序执行序列,但两者又有区别。进程是一个实体,每个进程有自己独立的状态,并有自己的专用数据段,创建进程时,必须建立和复制其专用数据段,线程则互相共享数据段。同一个程序中的所有线程只有一个数据段,所以,创建线程时不必重新建立和复制数据段。由于数据段建立和复制这方面的差异,使线程的建立和线程间的切换速度大大优于进程,另一方面,线程又具备进程的大多数优点。假设银行系统办理存款和取款手续,将帐本看成数据段。如果按进程这种机制,那么,当储户去存/取款时,银行应先把帐本复制一遍,为储户建立一个独立的帐本再结算。如果按线程机制,那么,银行里所有的出纳员都用同一个帐本,储户来办存/取款时,也从这个帐本直接结算。用线程机制省去了数据段复制这一步显然是线程独具的特点。由于多个线程共享一个数据段,所以,也出现了数据访问过程的互斥和同步问题,这使系统管理功能变得相对复杂。总的来说,一个多线程系统在提高系统的输入/输出速度、有效利用系统资源、改善计算机通信功能以及发挥多处理器硬件功能方面显示了很大优势。因此,一些最新的操作系统如Windows、Windows、WindowsNT等都提供了对多线程的支持。但是,在多线程操作系统下设计多线程的程序仍然是一个比较复杂和困难的工作。由于需要解决对数据段的共享,所以,原则上应该从程序设计角度采用加锁和释放措施,稍有不慎,便会使系统产生管理上的混乱。而Java从语言一级提供对多线程的支持,这样,可由语言和运行系统联合提供对共享数据段的管理功能和同步机制,使得多线程并行程序设计相对比较容易。2Java线程的生命周期每个线程都是和生命周期相联系的,一个生命周期含有多个状态,这些状态间可以互相转化。Java的线程的生命周期可以分为个状态;创建(new)状态;可运行(runnable)状态;不执行(notrunnable)状态;消亡(dead)状态。创建状态是指创建一个线程对应的对象的过程,Java系统中,些对象都是从Java.lang包内一个称为Thread的类用关键字new创建的。刚创建的线程不能执行,必须向系统进行注册、分配必要的资源后才能进入可运行状态,这个步骤是由start操作完成的,而处于可运行状态的线程也未必一定处于运行中,它有可能由于外部的I/O请求而处于不运行状态。进入消亡状态后,此线程就不再存在了。一个线程创建之后,总是处于其生命周期的个状态之一中,线程的状态表明此线程当前正在进行的活动,而线程的状态是可以通过程序来进行控制的,就是说,可以对线程进行操作来改变状态。这些操作包括启动(start)、终止(stop)、睡眠(sleep)、挂起(suspend)、恢复(resume)、等待(wait)和通知(notify)。每一个操作都对应了一个方法?这些方法是由软件包Java.lang提供的。通过各种操作,线程的个状态之间可按图所示进行转换。.创建(new)状态如果创建了一个线程而没有启动它,那么,此线程就处于创建状态。比如,下述语句执行以后,使系统有了一个处于创建状态的线程myThread:?ThreadmyThread=newMyThreadClass();其中,MyThreadClass()是Thread的子类,而Thread是由Java系统的Java.lang软件包提供的。处于创建状态的线程还没有获得应有的资源,所以,这是一个空的线程,线程只有通过启动后,系统才会为它分配资源。对处于创建状态的线程可以进行两种操作:一是启动(start)操作,使其进入可运行状态;二是终止(stop)操作,使其进入消亡状态。如果进入到消亡状态,那么,此后这个线程就不能进入其它状态,也就是说,它不复存在了。start方法是对应启动操作的方法,其具体功能是为线程分配必要的系统资源,将线程设置为可运行状态,从而可以使系统调度这个线程。.可运行(runnable)状态如果对一个处于创建状态的线程进行启动操作,则此线程便进入可运行状态。比如,用下列语句?myThread.start();??则使线程myThread进入可运行状态。上述语句实质上是调用了线程体即run()方法,注意,run()方法包含在myThread线程中,也就是先由java.lang包的Thread类将run()方法传递给子类MyThreadClass(),再通过创建线程由子类MyThreadClass,传递给线程myThread。线程处于可运行状态只说明它具备了运行条件,但可运行状态并不一定是运行状态,因为在单处理器系统中运行多线程程序,实际上在一个时间点只有一个线程在运行,而系统中往往有多个线程同时处于可运行状态,系统通过快速切换和调度使所有可运行线程共享处理器,造成宏观上的多线程并发运行。可见,一个线程是否处于运行状,除了必须处于可运行状态外,还取决于系统的调度。在可运行状态可以进行多种操作,最通常的是从run()方法正常退出而使线程结束,进入消亡状态。此,还可以有如下操作?挂起操作,通过调用suspend方法来实现;睡眠操作,通过调用sleep方法来实现;等待操作,通过调用wait方法来实现;退让操作,通过调用yield方法来实现;终止操作,通过调用stop方法来实现。前面三种操作都会使一个处于可运行状态的线程进入不可运行状态。比如,仍以myThread线程为例,当其处于可运行状态后,再用如下语句?myThread.sleep();则调用sleep方法使myThread线程睡眠s(ms)。这s内,此线程不能被系统调度运行,只有过s后,myThread线程才会醒来并自动回到可运行状态。如果一个线程被执行挂起操作而转到不可运行状态,则必须通过调用恢复(resume)操作,才能使这个线程再回到可运行状态。退让操作是使某个线程把CPU控制权提前转交给同级优先权的其他线程。对可运行状态的线程也可以通过调用stop方法使其进入消亡状态。.不可运行(notrunnable)状态不可运行状态都是由可运行状态转变来的。一个处于可运行状态的线程,如果遇到挂起(suspend)操作、睡眠(sleep)操作或者等待(wait)操作,就会进入不可运行状态。另外,如果一个线程是和I/O操作有关的,那么,在执行I/O指令时,由于外设速度远远低于处理器速度而使线程受到阻,从而进入不可运行状态,只有外设完成输入/输出之后,才会自动回到可运行状态。线程进入不可运行状态后,还可以再回到可运行状态,通常有三种途径使其恢复到可运行状态。一是自动恢复。通过睡眠(sleep)操作进入不可运行状态的线程会在过了指定睡眠时间以后自动恢复到可运行状态,由于I/O阻塞而进入不可运行状态的线程在外设完成I/O操作后,自动恢复到可运行状态。二是用恢复(resume)方法使其恢复。如果一个线程由于挂起(suspend)操作而从可运行状态进入不可运行状态,那么,必须用恢复(resume)操作使其再恢复到可运行状态。三是用通知(notify或notifyAll)方法使其恢复。如果一个处于可运行状态的线程由于等待(wait)操作而转入不可运行状态,那么,必须通过调用notify方法或notifyAll方法才能使其恢复到可运行状态,采用等待操作往往是由于线程需要等待某个条件变量,当获得此条件变量后,便可由notify或ontifyAll方法使线程恢复到可运行状态。恢复到可运行状态的每一种途径都是有针对性的,不能交叉。比如,对由于阻塞而进入不可运行状态的线程采用恢复操作将是无效的。在不可运行状态,也可由终止(stop)操作使其进入消亡状态。.消亡(dead)状态一个线程可以由其他任何一个状态通过终止(stop)操作而进入消亡状态。线程一旦进入消亡状态,那它就不再存在了,所以也不可能再转到其它状态。通常,在一个应用程序运行时,如果通过其它外部命令终止当前应用程序,那么就会调用(stop)方法终止线程。但是,最正常、最常见的途径是由于线程在可运行状态正常完成自身的任务而″寿终正寝″,从而进入消亡状态,这个完成任务的动作是由run方法实现的。3Java线程的两种创建途径一种途径是通过对Thread的继承来派生一个子类,再由此子类生成一个对象来实现线程的创建,这是比较简单直接的办法。Thread类包含在系统API提供的个软件包之一Java.lang中,Thread类中包含了很多与线程有关的方,其中,一个名为run的方法就是用来实现线程行为的。比如:?1importjava.lang.*?//引用lang包2classMangoextedsThread{3publicvoidrun(){4......5?}6?}上述程序段中,第1行语句引用软件包lang,这样做是为了给编译器一个信息,从而使后面程序中有关lang包中的方法可直接用方法名,而不必带前缀“Java.lang”。第2行语句是从lang包Thread派生一个子类Mango,而这个子类中提供了run方法的实现,这样,运行时,将由子类Mango的run方法置换父类Thread的run方法。不过这一步还没有创建线,必须由子类生成一个对象,并且进行启动操作,这样才能得到一个处于可运行状态的线程。生成对象其实就是完成线程的创建,而启动是对已创建的线程进行操作。具体语句如下:?Mangot=newMango();?t.start();?上面先用关键字new使线程进入创建状态,又调用start()方法使线程进入可运行状态。注意,start()方法是由Thread继承给子类Mango、然后又在生成对象时由对象t从类Mango得到的。另一种途径是通过一个类去继承接口runnable来实现线程的创建?而这个类必须提供runnable接口中定义的方法run()的实现。runnable是Java.lang包中的一个接口,在runnable接口中,只定义了一个抽象方法run()。所以,如用这种途径来创建线程,则应先由一个类连接接口runnable,并且提供run()方法的实现。比如,下面的程序段实现了与接口的连接。1publilassxyzimplementsRunnable{2inti;?3publicvoedrun(){4while(true){?5System.out.println(“Hello“+i++);6?}7?}8?}然后再创建一个线程?runnabler=newxyz();?Threadt=newThread(r);这种途径创建线程比第一种途径灵活。当一个类既需要继承一个父类又要由此创建一个线程时,由于Java不支持多重继承,这样,用第一种途径将行不通,因为,按此思路创建线程也是以继承的方法实现的。于是,就需要一个类既继承Thread类,又继承另一个父类。但用接口方法却能实现这个目标。4线程的启动和终止Thread的start()方法对应于启动操作,它完成两方面的功能:一方面是为线程分配必要的资源,使线程处于可运行状态,另一方面是调用线程的run()方法置换Thread的中run()方法或者置换runnable中的run()方法来运行线程。使用start()方法的语句很简单,即:ThreadName.start();下面的程序段先创建并启动线程myThread,然后使用sleep()方法让其睡眠ms即s,使其处于不可运行状态,过s后,线程又自动恢复到可运行状态。ThreadMyThread=newMyThreadClass();MyThread.start();??try{?MyThread.sleep();?}catch(InterrujptedExceptione){}

  ⒃java多线程机制中线程间可以共享相同的内存单元对还是错

  ⒄java多线程机制中线程间可以共享相同的内存单元是对的。根据查询相关公开信息显示,同一进程的多个线程间可以共享相同的内存单元,并可利用这些共享单元来实现数据交换、实时通信和必要的同步操作。

  ⒅java多线程开发的同步机制有哪些

  ⒆一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在java里边就是拿到某个同步对象的锁(一个对象只有一把锁;如果这个时候同步对象的锁被其他线程拿走了,他(这个线程就只能等了(线程阻塞在锁池等待队列中。取到锁后,他就开始执行同步代码(被synchronized修饰的代码;线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。这样就保证了同步代码在统一时刻只有一个线程在执行。众所周知,在Java多线程编程中,一个非常重要的方面就是线程的同步问题。关于线程的同步,一般有以下解决方法:.在需要同步的方法的方法签名中加入synchronized关键字。.使用synchronized块对需要进行同步的代码段进行同步。.使用JDK中提供的java.util.concurrent.lock包中的Lock对象。另外,为了解决多个线程对同一变量进行访问时可能发生的安全性问题,我们不仅可以采用同步机制,更可以通过JDK.中加入的ThreadLocal来保证更好的并发性。

  ⒇java多线程运行机制

  ⒈首先子线程不是独立的空间啊!要不也有同步锁了!java中运行多线程时是一会运行这个线程,一会运行那个线程……随机运行的。因为运行的速度快时间短,所以就给人感觉线程是同时运行的。只要出错了,java程序立马停止运行!

  ⒉java多线程是怎么回事

  ⒊进程是程序在处理机中的一次运行。一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立。所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销。线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。所以线程是轻量级的任务,它们之间的通信和转换只需要较小的系统开销。Java支持多线程编程,因此用Java编写的应用程序可以同时执行多个任务。Java的多线程机制使用起来非常方便,用户只需关注程序细节的实现,而不用担心后台的多任务系统。Java语言里,线程表现为线程类。Thread线程类封装了所有需要的线程操作控制。在设计程序时,必须很清晰地区分开线程对象和运行线程,可以将线程对象看作是运行线程的控制面板。在线程对象里有很多方法来控制一个线程是否运行,睡眠,挂起或停止。线程类是控制线程行为的唯一的手段。一旦一个Java程序启动后,就已经有一个线程在运行。可通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。classThreadTest{publicstaticvoidmain(Stringargs){Threadt=Thread.currentThread();t.setName(“单线程“);//对线程取名为“单线程“t.setPriority();//设置线程优先级为,最高为,最低为,默认为System.out.println(“Therunningthread:“+t);//显示线程信息try{for(inti=;i《;i++){System.out.println(“Sleeptime“+i);Thread.sleep();//睡眠毫秒}}catch(InterruptedExceptione){//捕获异常System.out.println(“threadhaswrong“);}}}多线程的实现方法继承Thread类可通过继承Thread类并重写其中的run()方法来定义线程体以实现线程的具体行为,然后创建该子类的对象以创建线程。在继承Thread类的子类ThreadSubclassName中重写run()方法来定义线程体的一般格式为:publilassThreadSubclassNameextendsThread{publicThreadSubclassName(){.....//编写子类的构造方法,可缺省}publicvoidrun(){.....//编写自己的线程代码}}用定义的线程子类ThreadSubclassName创建线程对象的一般格式为:ThreadSubclassNameThreadObject=newThreadSubclassName();然后,就可启动该线程对象表示的线程:ThreadObject.start();//启动线程应用继承类Thread的方法实现多线程的程序。本程序创建了三个单独的线程,它们分别打印自己的“HelloWorld!”。classThreadDemoextendsThread{privateStringwhoami;privateintdelay;publicThreadDemo(Strings,intd){whoami=s;delay=d;}publicvoidrun(){try{sleep(delay);}catch(InterruptedExceptione){}System.out.println(“HelloWorld!“+whoami+““+delay);}}publilassMultiThread{publicstaticvoidmain(Stringargs){ThreadDemot,t,t;t=newThreadDemo(“Thread“,(int)(Math.random()*));t=newThreadDemo(“Thread“,(int)(Math.random()*));t=newThreadDemo(“Thread“,(int)(Math.random()*));t.start();t.start();t.start();}}实现Runnable接口编写多线程程序的另一种的方法是实现Runnable接口。在一个类中实现Runnable接口(以后称实现Runnable接口的类为Runnable类),并在该类中定义run()方法,然后用带有Runnable参数的Thread类构造方法创建线程。创建线程对象可用下面的两个步骤来完成:()生成Runnable类ClassName的对象ClassNameRunnableObject=newClassName();()用带有Runnable参数的Thread类构造方法创建线程对象。新创建的线程的指针将指向Runnable类的实例。用该Runnable类的实例为线程提供run()方法---线程体。ThreadThreadObject=newThread(RunnableObject);然后,就可启动线程对象ThreadObject表示的线程:ThreadObject.start();在Thread类中带有Runnable接口的构造方法有:publicThread(Runnabletarget);publicThread(Runnabletarget,Stringname);publicThread(Stringname);publicThread(ThreadGroupgroup,Runnabletarget);publicThread(ThreadGroupgroup,Runnabletarget,Stringname);其中,参数Runnabletarget表示该线程执行时运行target的run()方法,Stringname以指定名字构造线程,ThreadGroupgroup表示创建线程组。用Runnable接口实现的多线程。classTwoThreadimplementsRunnable{TwoThread(){Threadt=Thread.currentThread();t.setName(“第一主线程“);System.out.println(“正在运行的线程:“+t);Threadt=newThread(this,“第二线程“);System.out.println(“创建第二线程“);t.start();try{System.out.println(“第一线程休眠“);Thread.sleep();}catch(InterruptedExceptione){System.out.println(“第一线程有错“);}System.out.println(“第一线程退出“);}publicvoidrun(){try{for(inti=;i《;i++){System.out.println(“第二线程的休眠时间:”+i);Thread.sleep();}}catch(InterruptedExceptione){System.out.println(“线程有错“);}System.out.println(“第二线程退出“);}publicstaticvoidmain(Stringargs){newTwoThread();}}程序运行结果如下:正在运行的线程:Thread[第一主线程,,main创建第二线程第一线程休眠第二线程的休眠时间:第二线程的休眠时间:第二线程的休眠时间:第一线程退出第二线程的休眠时间:第二线程的休眠时间:第二线程退出

  ⒋在Java中多线程的实现方法有哪些,如何使用

  ⒌Java多线程的创建及启动

  ⒍Java中线程的创建常见有如三种基本形式

  ⒎继承Thread类,重写该类的run()方法。

  ⒏classMyThreadextendsThread{

  ⒐??privateinti=;

  ⒑??Override

  ⒒??publicvoidrun(){

  ⒓????for(i=;i《;i++){

  ⒔??????System.out.println(Thread.currentThread().getName()+““+i);

  ⒕publilassThreadTest{

  ⒖??publicstaticvoidmain(Stringargs){

  ⒗????for(inti=;i《;i++){

  ⒘??????System.out.println(Thread.currentThread().getName()+““+i);

  ⒙??????if(i==){

  ⒚????????ThreadmyThread=newMyThread();??//创建一个新的线程?myThread?此线程进入新建状态

  ⒛????????ThreadmyThread=newMyThread();??//创建一个新的线程myThread此线程进入新建状态

  ????????myThread.start();??????????//调用start()方法使得线程进入就绪状态

  ????????myThread.start();??????????//调用start()方法使得线程进入就绪状态

  如上所示,继承Thread类,通过重写run()方法定义了一个新的线程类MyThread,其中run()方法的方法体代表了线程需要完成的任务,称之为线程执行体。当创建此线程类对象时一个新的线程得以创建,并进入到线程新建状态。通过调用线程对象引用的start()方法,使得该线程进入到就绪状态,此时此线程并不一定会马上得以执行,这取决于CPU调度时机。

  实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。

  classMyRunnableimplementsRunnable{

  ??privateinti=;

  ??Override

  ??publicvoidrun(){

  ????for(i=;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  publilassThreadTest{

  ??publicstaticvoidmain(Stringargs){

  ????for(inti=;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  ??????if(i==){

  ????????RunnablemyRunnable=newMyRunnable();//创建一个Runnable实现类的对象

  ????????Threadthread=newThread(myRunnable);//将myRunnable作为Threadtarget创建新的线程

  ????????Threadthread=newThread(myRunnable);

  ????????thread.start();//调用start()方法使得线程进入就绪状态

  ????????thread.start();

  相信以上两种创建新线程的方式大家都很熟悉了,那么Thread和Runnable之间到底是什么关系呢?我们首先来看一下下面这个例子。

  publilassThreadTest{

  ??publicstaticvoidmain(Stringargs){

  ????for(inti=;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  ??????if(i==){

  ????????RunnablemyRunnable=newMyRunnable();

  ????????Threadthread=newMyThread(myRunnable);

  ????????thread.start();

  classMyRunnableimplementsRunnable{

  ??privateinti=;

  ??Override

  ??publicvoidrun(){

  ????System.out.println(“inMyRunnablerun“);

  ????for(i=;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  classMyThreadextendsThread{

  ??privateinti=;

  ??publicMyThread(Runnablerunnable){

  ????super(runnable);

  ??Override

  ??publicvoidrun(){

  ????System.out.println(“inMyThreadrun“);

  ????for(i=;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  同样的,与实现Runnable接口创建线程方式相似,不同的地方在于

  Threadthread=newMyThread(myRunnable);

  那么这种方式可以顺利创建出一个新的线程么?答案是肯定的。至于此时的线程执行体到底是MyRunnable接口中的run()方法还是MyThread类中的run()方法呢?通过输出我们知道线程执行体是MyThread类中的run()方法。其实原因很简单,因为Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。

  publicinterfaceRunnable{

  ??publicabstractvoidrun();

  我们看一下Thread类中对Runnable接口中run()方法的实现:

  publicvoidrun(){

  if(target!=null){

  target.run();

  也就是说,当执行到Thread类中的run()方法时,会首先判断target是否存在,存在则执行target中的run()方法,也就是实现了Runnable接口并重写了run()方法的类中的run()方法。但是上述给到的列子中,由于多态的存在,根本就没有执行到Thread类中的run()方法,而是直接先执行了运行时类型即MyThread类中的run()方法。

  使用Callable和Future接口创建线程。具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。

  看着好像有点复杂,直接来看一个例子就清晰了。

  publilassThreadTest{

  ??publicstaticvoidmain(Stringargs){

  ????Callable《Integer》myCallable=newMyCallable();??//创建MyCallable对象

  ????FutureTask《Integer》ft=newFutureTask《Integer》(myCallable);//使用FutureTask来包装MyCallable对象

  ????for(inti=;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  ??????if(i==){

  ????????Threadthread=newThread(ft);?//FutureTask对象作为Thread对象的target创建新的线程

  ????????thread.start();???????????//线程进入到就绪状态

  ????System.out.println(“主线程for循环执行完毕..“);

  ??????intsum=ft.get();??????//取得新创建的新线程中的call()方法返回的结果

  ??????System.out.println(“sum=“+sum);

  ????}catch(InterruptedExceptione){

  ??????e.printStackTrace();

  ????}catch(ExecutionExceptione){

  ??????e.printStackTrace();

  classMyCallableimplementsCallable《Integer》{

  ??privateinti=;

  ??//与run()方法不同的是,call()方法具有返回值

  ??Override

  ??publicIntegercall(){

  ????intsum=;

  ????for(;i《;i++){

  ??????System.out.println(Thread.currentThread().getName()+““+i);

  ??????sum+=i;

  ????returnsum;

  首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target。那么看下FutureTask类的定义:

  publilassFutureTask《V》implementsRunnableFuture《V》{

  publicinterfaceRunnableFuture《V》extendsRunnable,Future《V》{

  ??voidrun();

  于是,我们发现FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。

  执行下此程序,我们发现sum=永远都是最后输出的。而“主线程for循环执行完毕..”则很可能是在子线程循环中间输出。由CPU的线程调度机制,我们知道,“主线程for循环执行完毕..”的输出时机是没有任何问题的,那么为什么sum=会永远最后输出呢?

  原因在于通过ft.get()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ft.get()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。

  上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。

  你好,本题已解答,如果满意

  请点右下角“采纳答案”。

  java多线程是什么

  线程定义比较抽象,简单的说就是一个代码执行流。许多执行流可以混合在一起由CPU调度。线程是允许各种任务交互执行的方式。Java的线程在操作系统的实现模式依系统不同而不同,可能是系统级别的进程或线程,但对于程序员来说并没有影响。任务交互的一个好处是增加程序响应。如一个界面程序执行一段耗时的数据库查询,使用单独的线程可以让界面依然响应用户的其他输入,而单线程只能等待查询结束再处理。JVM以及操作系统会优先处理优先级别高的线程,但不代表这些线程一定会先完成。设定优先级只能建议系统更快的处理,而不能强制。另外,在运行时,并没有按照函数分界,而是按照机器码/汇编码分界。也就是说不保证任何一段代码是被完整而不打断的执行的(除非你已经使用同步手段。正由于如此,各种线程同步的方法应运而生。

  java提供了哪些接口和类实现多线程机制

  JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

  作者natrium一理解多线程多线程是这样一种机制它允许在程序中并发执行多个指令流每个指令流都称为一个线程彼此间互相独立线程又称为轻量级进程它和进程一样拥有独立的执行控制由操作系统负责调度区别在于线程没有独立的存储空间而是和所属进程中的其它线程共享一个存储空间这使得线程间的通信远较进程简单多个线程的执行是并发的也就是在逻辑上同时而不管是否是物理上的同时如果系统只有一个CPU那么真正的同时是不可能的但是由于CPU的速度非常快用户感觉不到其中的区别因此我们也不用关心它只需要设想各个线程是同时执行即可多线程和传统的单线程在程序设计上最大的区别在于由于各个线程的控制流彼此独立使得各个线程之间的代码是乱序执行的由此带来的线程调度同步等问题将在以后探讨二在Java中实现多线程我们不妨设想为了创建一个新的线程我们需要做些什么?很显然我们必须指明这个线程所要执行的代码而这就是在Java中实现多线程我们所需要做的一切!真是神奇!Java是如何做到这一点的?通过类!作为一个完全面向对象的语言Java提供了类javalangThread来方便多线程编程这个类提供了大量的方法来方便我们控制自己的各个线程我们以后的讨论都将围绕这个类进行那么如何提供给Java我们要线程执行的代码呢?让我们来看一看Thread类Thread类最重要的方法是run()它为Thread类的方法start()所调用提供我们的线程所要执行的代码为了指定我们自己的代码只需要覆盖它!方法一继承Thread类覆盖方法run()我们在创建的Thread类的子类中重写run()加入线程所要执行的代码即可下面是一个例子publilassMyThreadextendsThread{intcount=number;publicMyThread(intnum){number=num;Systemoutprintln(创建线程+number);}publicvoidrun(){while(true){Systemoutprintln(线程+number+:计数+count);if(++count==)return;}}publicstaticvoidmain(Stringargs){for(inti=;i《;i++)newThread(newMyThread(i+)).start();}}严格地说,创建Thread子类的实例也是可行的,但是必须注意的是,该子类必须没有覆盖Thread类的run方法,否则该线程执行的将是子类的run方法,而不是我们用以实现Runnable接口的类的run方法,对此大家不妨试验一下。使用Runnable接口来实现多线程使得我们能够在一个类中包容所有的代码,有利于封装,它的缺点在于,我们只能使用一套代码,若想创建多个线程并使各个线程执行不同的代码,则仍必须额外创建类,如果这样的话,在大多数情况下也许还不如直接用多个类分别继承Thread来得紧凑。综上所述,两种方法各有千秋,大家可以灵活运用。下面让我们一起来研究一下多线程使用中的一些问题。三:线程的四种状态.新状态:线程已被创建但尚未执行(start()尚未被调用。.可执行状态:线程可以执行,虽然不一定正在执行。CPU时间随时可能被分配给该线程,从而使得它执行。.死亡状态:正常情况下run()返回使得线程死亡。调用stop()或destroy()亦有同样效果,但是不被推荐,前者会产生异常,后者是强制终止,不会释放锁。.阻塞状态:线程不会被分配CPU时间,无法执行。四:线程的优先级线程的优先级代表该线程的重要程度,当有多个线程同时处于可执行状态并等待获得CPU时间时,线程调度系统根据各个线程的优先级来决定给谁分配CPU时间,优先级高的线程有更大的机会获得CPU时间,优先级低的线程也不是没有机会,只是机会要小一些罢了。你可以调用Thread类的方法getPriority()和setPriority()来存取线程的优先级,线程的优先级界于(MIN_PRIORITY)和(MAX_PRIORITY)之间,缺省是(NORM_PRIORITY)。五:线程的同步由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块。.synchronized方法:通过在方法声明中加入synchronized关键字来声明synchronized方法。如:publicsynchronizedvoidaessVal(intnewVal);synchronized方法控制对类成员变量的访问:每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为synchronized的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁,从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized。在Java中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为synchronized,以控制其对类的静态成员变量的访问。synchronized方法的缺陷:若将一个大的方法声明为synchronized将会大大影响效率,典型地,若将线程类的方法run()声明为synchronized,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何synchronized方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为synchronized,并在主方法中调用来解决这一问题,但是Java为我们提供了更好的解决办法,那就是synchronized块。.synchronized块:通过synchronized关键字来声明synchronized块。语法如下:synchronized(syncObject){//允许访问控制的代码}synchronized块是这样一个代码块,其中的代码必须获得对象syncObject(如前所述,可以是类实例或类的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。六:线程的阻塞为了解决对共享存储区的访问冲突,Java引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题,Java引入了对阻塞机制的支持。阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪,学过操作系统的同学对它一定已经很熟悉了。Java提供了大量方法来支持阻塞,下面让我们逐一分析。.sleep()方法:sleep()允许指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU时间,指定的时间一过,线程重新进入可执行状态。典型地,sleep()被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。.suspend()和resume()方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume()被调用,才能使得线程重新进入可执行状态。典型地,suspend()和resume()被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后lishixinzhi/Article/program/Java/gj//

您可能感兴趣的文章:

相关文章