ImageVerifierCode 换一换
格式:DOCX , 页数:19 ,大小:23.36KB ,
资源ID:9025857      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9025857.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(线程已阅.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

线程已阅.docx

1、线程已阅线程1、 线程的状态线程的状态表示线程在某段时间内进行的活动和将要进行的任务。线程有创建、就绪、运行、阻塞、死亡5种状态。1 创建状态实例化Thread对象,但没有调用start()方法时的状态。例如:ThreadTest tt=new ThreadTest();或者Thread t=new Thread(tt);此时虽然创建了Thread对象,但是他们暂时不能通过isAlive()测试。2 就绪状态程序有资格运行,当调度程序还没有把它选为线程运行时所处的状态。此时,线程具备了运行的条件,一旦被选中马上就能运行。线程创建后,调用了start()方法,线程不处于运行状态,但能通过isAl

2、ive()测试。在线程运行后,或者从被阻塞、等待或者睡眠状态回来之后,线程首先进入就绪状态。3 运行状态从就绪状态池(是池,不是队列)中被选择为当前执行的线程所处的状态。4 等待、阻塞或者睡眠状态线程依然是活的,但是缺少运行的条件,一旦具备了条件就可以转为就绪状态(不能直接转为运行状态)。另外,suspend()和stop()方法已经被废弃了,比较危险,不要再使用了。5 死亡状态一个线程的run()方法运行结束,那么该线程就完成了它的使命,它的栈结构将解散,也就是死亡了。但是该线程仍然是一个Thread对象,仍可以被引用这一点与其他对象一样,而且被引用的对象也不会被垃圾回收器回收。 一旦线程死

3、去,他就永远不能重新启动了,也就是说,不能再用start()方法让它运行。创建线程有两种方式。继承java.lang.Thread类public class ThreadTest extends Thread public void run() System.out.println(something run here!); public void run(String s) System.out.println(string in run is+s); public static void main(String args) ThreadTest tt=new ThreadTest(); t

4、t.start(); tt.run(it wont auto run); 运行结果如下:string in run isit wont auto runsomething run here!注意:是否与想象的顺序相反了?为什么呢?一旦调用了start()方法,必须给JVM留足时间,让它配置进程。而在JVM配置完成之前,重载的run(String s)方法被调用了,结果反而先输出了“string in run is it wont auto run”。之后,tt线程完成了配置,输出了“something run here!”这个结论是比较容易验证。修改上面的程序,在“tt.start();”语句

5、后面加上语句“for(int i=0;i10000;i+);”.主线程必须执行运算量比较大的for循环,只有执行完for循环才能运行后面的“tt.run(“it wont auto run!”);”语句。此时,因为有足够的时间完成线程的配置,所以修改后的程序运行结果如下: something run here stirng in run is it wont auto run!注意:这种输出结果的顺序是没有保障!不要依赖循环耗时!Thread类有许多管理线程的方法,包括创建、启动和暂停他们,所有的操作都是从run()方法开始,并且在run()方法内编写需要在独立线程内执行的代码。run()方法

6、可以调用其他方法,但是执行的线程总是通过调用run()开始。 没有参数的run()方法是自动被调用的,而带参数的run()是被重载的,必须显示调用。上面示例中创建线程的方式很简单,但不是最好的方案。Java是单继承结构的,如果继承了Thread类,那么就不能继承其它的类了,应该把继承的机会留给别的类。实现java.lang.Runnable接口 public class ThreadTest implements Runnable public void run() System.out.println(something run here!); public static void main

7、(String args) ThreadTest tt=new ThreadTest(); Thread t1=new Thread(tt); Thread t2=new Thread(tt); t1.start(); t2.start(); /new Thread(tt).start(); 这种方式把线程相关的代码和线程要执行的代码分离出来。 另一种常见的方式是参数形式的匿名内部类创建方式,示例代码如下 public class ThreadTest public static void main(String args) Thread t=new Thread(new Runnable()

8、 public void run() System.out.println(anonymous thread); ); t.start(); 在调用start()方法开始执行线程之前,线程的状态还不是活的。测试程序如下: public class ThreadTest implements Runnable public void run() System.out.println(something run here!); public static void main(String args) ThreadTest tt=new ThreadTest(); Thread t1=new Thr

9、ead(tt); System.out.println(t1.isAlive(); t1.start(); System.out.println(t1.isAlive(); 结果输出:falsetrueisAlivve()方法用于确定一个线程是否已经启动,而且还没完成run()方法。注意:线程的启动要调用start()方法,只有这样才能创建新的调用栈。而直接调用run()方法的话,就不会调用新调用栈,也就不会创建新的线程,run方法就与普通的方法没什么两样了。2、 线程同步线程同步指多个线程同时访问某资源时,采用一系列的机制以保证同时最多只能有一个线程访问该资源。线程共享了相同的资源。但是在某

10、些重要的情况下,一次只能让一个线程来访问共享资源,例如,作为银行账户这样的共享资源,如果多个线程可以同时使用该资源,就会出现银行账户数据安全上的问题。1 共享变量要使多个线程在同一个程序中有用,必须在某种方法实现线程间互相通信或共享结果,最简单方法是使用共享变量。确保变量从一个线程正确传播到另一个线程,以防止当一个线程正在更新一些相关数据项时,另一个线程看到不一致的中间结果,需要采取线程同步。2 存在于同一个内存空间中的所有线程线程与进程有许多共同点,不同的是线程与统一进程中的其他线程共享相同的进程上下文,包括内存空间。只要访问共享变量(静态变量或实例变量),线程就可以方便地互相交换数据,但必

11、须确保线程以受控的方式访问共享变量,以免它们互相干扰对方的更改。3 受控访问的同步为确保可以在线程之间以受控方式共享数据,Java语言提供了两个关键字:synchronized和volatile。Synchronized有两个重要含义: 一次只有一个线程可以执行代码的受保护部分 一个线程更改的数据对于其他线程是可见的。4 确保共享数据更改的可见性同步可以让用户确保线程看到一致的内存视图。如果没有同步,数据很容易处于不一致的状态。例如,一个线程正在更新两个相关值,而另一个线程正在读取这两个值,有可能在第1个线程只更新了一个值,还没有来得及更新另一个值的时候,调度第2个线程运行,第2个线程就会看到

12、一个旧值和一个新值。Volatile比同步更简单,只适合于控制对基本变量(整数、布尔变量等)的单个实例的访问。当一个变量被声明为volatile,任何对该变量的写操作都会绕过告诉缓存,直接写入主内存,而任何对该变量的读取也都绕过告诉缓存,直接取自主内存。这表示所有线程在任何时候看到的volatile变量值都相同。5 用锁保护的原子代码块Volatile对于确保每个线程看到最新的变量值非常有用,但实际上经常需要保护代码片段,同步使用监控器(monitor)或锁的概念,以协调对特定代码块的访问。每个Java对象都有一个相关的锁,同一时间只能有一个线程持有Java锁。当线程进入synchronize

13、d代码块时,线程会阻塞并等待,直到锁可用。当线程处于就绪状态时,并且获得锁后,将执行代码块,当控制退出受保护的代码块,即到达了代码块的末尾或者抛出了没有在synchronized块中捕获的异常时,它就会释放该锁。这样,每次只有一个线程可以执行受给定监控器保护的代码块。从其他线程的角度看,该代码块可以看做是原子的,它要么全部执行,要么根本不执行。6 简单的同步示例使用synchronized块可以将一组相关更新作为一个集合来执行,而不必担心其他线程中断或得到意外的结果。以下示例将打印“1 0”或者“0 1”,如果没有同步,他还会打印“1 1”或“0 0”。 public class SynExa

14、mple private static Object lockObject=new Object(); private static class Thread1 extends Thread public void run() synchronized(lockObject) int x,y; x=y=0; System.out.println(x); private static class Thread2 extends Thread public void run() synchronized(lockObject) int x,y; x=y=1; System.out.println(

15、y); public static void main(String args) new Thread1().run(); new Thread2().run(); 在这两个线程中都必须使用同步,以便使程序正确工作。7 Java锁定Java锁定可以保护许多代码块或方法,每次只有一个线程可以持有锁。代码块由锁保护并不表示两个线程不能同时执行该代码块,只表示如果两个线程正在等待相同的锁,则他们不能同时执行该代码。在以下示例中,两个线程可以同时不受限制地执行setLastAccess()方法中的synchronized块,因为每个线程有一个不同的thingie值。因此,synchronized代码块

16、受到两个正在执行的线程中不同锁的保护。 public class SynExample public static class Thingie private Date laseAccess; public synchronized void setLastAccess(Date date) this.laseAccess=date; public static class MyThread extends Thread private Thingie thingie; public MyThread(Thingie thingie) this.thingie=thingie; public

17、void run() thingie.setLastAccess(new Date(); public static void main(String args) Thingie thingie1=new Thingie(); Thingie thingie2=new Thingie(); new MyThread(thingie1).start(); new MyThread(thingie2).start(); 8 同步的方法创建synchronized块的最简单方法是将方法声明为synchronized。这表示致在进入方法主体之前,调用者必须获得锁,示例代码如下: public clas

18、s Point public synchronized void setXY(int x,int y) this.x=x; this.y=y; 对于普通的synchronized方法,这个锁是一个对象将针对它调用方法。对于静态synchronized方法,这个锁与Class对象相关的监控器,在该对象中声明了该方法。 setXY()方法被声明为synchronized并不表示两个不同的线程不能同时执行setXY()方法,只要他们调用不同的Point实例的setXY()方法就可以同时执行。对于同一个Point实例一次只能有一个线程执行setXY()方法或Point的任何其他synchronized

19、方法。9 同步的块Synchronized块的语法比synchronized方法稍微复杂一点,因为还需要显示地指定锁要保护哪个块。 public class Point public void setXY(int x,int y) synchronized(this) this.x=x; this.y=y; 使用this引用锁很常见,但这并不是必需的。使用this引用作为锁表示该代码块将与这个类中的synchronized方法使用同一个锁。由于同步防止了多个线程同时执行一个代码块,因此性能上就有问题,即使在单处理器系统上,最好在尽可能最小的需要保护的代码块上使用同步。访问基于堆栈的局部变量从来

20、不需要受到保护,因为他们只能被自己所属的线程访问。10 大多数类并没有同步因为同步会带来小小的性能损失,大多数通用类,如java.util中的Collection类,不在内部使用同步。这表示在没有附加同步的情况下,不能在多个线程中使用诸如HashMap这样的类。3、 线程转换线程存在着创建状态、就绪状态、运行状态、阻塞状态和死亡状态。那么各个状态之间是如何转换的呢?如何利用线程的状态转换来完成相应的任务?深入理解线程转换是灵活使用Java线程的基础。 在Java线程中,正在运行的线程可以转换为不可运行状态,但是线程不可从运行状态直接转换为运行状态,而是首先转换为运行状态,如下图所示。 Thre

21、ad类的常用方法如下所示。 final Boolean isAlive():用来的确定线程是活动线程还是死亡线程。如果线程已经启动并还没有终止,那么就是活动状态,返回true。 final int getPriority():返回当前状态的优先级 final void setPriority(int newPriority):改变线程的优先级 static void yield():使线程暂时停止运行 static void sleep(long millisec):指定当前线程的休眠时间,然后继续运行。 final void join():调用该方法的某线程,将当前线程与该线程“合并”,即等

22、待该线程结束,再恢复当前线程的运行。 void interrupt():中断调用此方法的线程。在等待通知、休眠或者阻塞以等待挂起完成的状态,线程会抛出InterruptedException异常。1 线程的调度和优先级 线程调用的意义在于JVM应对运行的多个线程进行系统级的协调,以避免多个线程争用有限资源而导致应用系统死机或者崩溃。Java定义了线程的优先级策略,Java线程的优先级分为10个等级,分别用110之间的数字表示。数字越大表示线程的优先级越高。相应地,在Thread类中定义了表示线程最低、最高和普通优先级的成员变量MIN-PRIORITY,MAX-PRIORITY和NOMAL-PR

23、IORITY,代表的优先级分别为1、10、5。当一个线程对象被创建时,其默认的线程优先级是5.为了控制线程的运行策略,Java定义了线程调度器来监控系统中处于就绪状态的所有线程。线程调度器按照线程的优先级决定哪个线程投入处理器运行。在多个线程处于就绪状态的条件下,具有高优先级的线程会在低优先级线程之前得到执行。线程调度器同样采用“抢占式”策略来调度线程执行,即当前线程执行过程中有较高优先级的线程进入就绪状态,则高优先级的线程立即被调度执行。具有相同优先级的线程采用轮转的方式来共同分配CPU时间片。在应用程序中设置线程优先级的方法很简单,在创建线程对象之后可以调用线程对象的setPriority

24、()方法改变该线程的运行优先级,同样可以调用getPriority()方法获取当前线程的优先级。在Java中比较特殊的线程是被称为守护线程(Daemon)的低级别线程。这个线程具有最低的优先级,用于为系统中的其他对象和线程提供服务。将一个用户线程设置为守护进程的方式是线程对象创建之前调用线程对象的setDaemon()方法。典型的守护线程例子是JVM中的系统资源自动回收线程,它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。2 运行和挂起通过调用strat()方法后,线程就进入了准备运行状态。进入准备运行阶段后,线程才能够获得运行的资格,即获得CPU的时间。注意:系统线程调度器

25、来决定哪个线程可以运行并确定其运行的时间,也就是说,线程具有不可预知性。 yield()方法调用线程Thread类的yield()方法将会导致当前线程从运行状态转换为准备运行状态。使用yield()方法的好处是可以让出CPU的时间,供其他线程使用。典型的例子就是用户需要进行长时间计算的线程(例如计算PI值),通过“取消”操作来获得快速的系统反应,从而预防假的死机现象。一个使用yield()方法的示例如下: public class TestYield public static void main(String args) MyThread t1=new MyThread(t1); MyThr

26、ead t2=new MyThread(t12); t1.start(); t2.start(); class MyThread extends Thread MyThread(String s) super(s); public void run() for(int i=0;i100;i+) System.out.println(getName()+:+i); if(i%10=0) yield(); sleep()方法sleep()使当前线程(即调用该方法的线程)暂时执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁,也就是说如果有synchronized同步块,其他线程仍然不能访问

27、共享数据注意:该方法要捕获异常。例如有两个线程同时执行(没有synchronized),一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY。如果没有sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行。但当高优先级的线程调用sleep(5000)后,低优先级就有机会执行了。总之,sleep()可以使低优先级的线程得到执行的机会,也可以让同优先级、高优先级的线程有执行的机会。3 wait()和notify()通常,多线程之间需要协调工作,例如两个人共用一个卫生间(每次只能一个人用),一个人必须等待另一人用完,得知没有人使用的时候才能使用卫生间。以上逻辑

28、简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait()和notify()。等待机制与锁机制是密切相关的。例如: synchronized(obj) while(!condition) obj.wait(); obj.dosomeThing(); 当线程A获得了obj锁后,发现条件condition不满足,无法继续下移处理,于是线程A就等待(调用wait()方法)。在另一线程B中,如果B更改了某些条件,使得线程A 的condition条件满足了,就可以唤醒线程A: synchronized(obj) condition=tru

29、e; obj.notify(); 如果以使用卫生间作为示例,加入他们都要刷牙和洗脸。他们是这样约定的:第一个人先刷牙,然后第二个人刷牙;第一个人洗脸,然后第二个人洗脸。程序代码如下:public class Syn public static void main(String args) TwoPeople.ONE.start(); TwoPeople.TWO.start(); class TwoPeople extends Thread private int i; static Thread ONE=new TwoPeople(1); static Thread TWO=new TwoPeople(2); static Object washroom=new Object(); private TwoPeople(int i) this.i=i; private void brush() System.out.println(People +i+ is brushing!); try Thread.sleep(2000); catch(Exception e) e.printStackTrace(); /延迟两秒看结果 System.out.println(People +i+ has brushed!);

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1