Java多线程编程学习

上传人:痛*** 文档编号:93281946 上传时间:2022-05-20 格式:DOC 页数:10 大小:72KB
收藏 版权申诉 举报 下载
Java多线程编程学习_第1页
第1页 / 共10页
Java多线程编程学习_第2页
第2页 / 共10页
Java多线程编程学习_第3页
第3页 / 共10页
资源描述:

《Java多线程编程学习》由会员分享,可在线阅读,更多相关《Java多线程编程学习(10页珍藏版)》请在装配图网上搜索。

1、文档供参考,可复制、编制,期待您的好评与关注! 在线程的Thread对象上调用start()方法,而不是run()或者别的方法。1、新状态:线程对象已经创建,还没有在其上调用start()方法。2、可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。3、运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。4、等待/阻塞/睡眠状态:这是线程有资格运行时它所处的状态。实际上这个三状态组合为

2、一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。5、死亡态:当线程的run()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。1、调用Thread.sleep():使当前线程睡眠至少多少毫秒(尽管它可能在指定的时间之前被中断)。2、调用Thread.yield():不能保障太多事情,尽管通常它会让当前运行线程回到可运行性状态

3、,使得有相同优先级的线程有机会执行。3、调用join()方法:保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。除了以上三种方式外,还有下面几种特殊情况可能使线程离开运行状态:1、线程的run()方法完成。2、在对象上调用wait()方法(不是在线程上调用)。3、线程不能在对象上获得锁定,它正试图运行该对象的方法代码。4、线程调度程序可以决定将当前运行状态移动到可运行状态,以便让另一个线程获得运行机会,而不需要任何理由。Java中每个对象都有一个内置锁当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当

4、前实例(this实例)有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。当程序运行到synchronized同步方法或代码块时才该对象锁才起作用。一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放。释放锁是指持锁线程退出了synchronized同步方法或代码块。二、同步和锁定关于锁和同步,有一下几个要点:1)、只能同步方法,而不能同步变量和类;2)、每个对象只有一个锁;当提到同步时,应该清楚在什么上同步?也就是说,在

5、哪个对象上同步?3)、不必同步类中所有的方法,类可以同时拥有同步和非同步方法。4)、如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。5)、如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制。6)、线程睡眠时,它所持的任何锁都不会释放。7)、线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。8)、同步

6、损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块。9)、在使用同步代码块时候,应该指定在哪个对象上同步,也就是说要获取哪个对象的锁。例如: public int fix(int y) synchronized (this) x = x - y; return x; 当然,同步方法也可以改写为非同步方法,但功能完全一样的,例如: public synchronized int getX() return x+; 与 public int getX() synchronized (this) return x; 效果是完全一样的。三、静态方法同步要同步静态

7、方法,需要一个用于整个类对象的锁,这个对象是就是这个类(XXX.class)。例如:public static synchronized int setName(String name) Xxx.name = name;等价于public static int setName(String name) synchronized(Xxx.class) Xxx.name = name; 四、如果线程不能不能获得锁会怎么样如果线程试图进入同步方法,而其锁已经被占用,则线程在该对象上被阻塞。实质上,线程进入该对象的的一种池中,必须在哪里等待,直到其锁被释放,该线程再次变为可运行或运行为止。当考虑阻塞时

8、,一定要注意哪个对象正被用于锁定:1、调用同一个对象中非静态同步方法的线程将彼此阻塞。如果是不同对象,则每个线程有自己的对象的锁,线程间彼此互不干预。2、调用同一个类中的静态同步方法的线程将彼此阻塞,它们都是锁定在相同的Class对象上。3、静态同步方法和非静态同步方法将永远不会彼此阻塞,因为静态方法锁定在Class对象上,非静态方法锁定在该类的对象上。4、对于同步代码块,要看清楚什么对象已经用于锁定(synchronized后面括号的内容)。在同一个对象上进行同步的线程将彼此阻塞,在不同对象上锁定的线程将永远不会彼此阻塞。五、何时需要同步在多个线程同时访问互斥(可交换)数据时,应该同步以保护

9、数据,确保两个线程不会同时修改更改它。对于非静态字段中可更改的数据,通常使用非静态方法访问。对于静态字段中可更改的数据,通常使用静态方法访问。如果需要在非静态方法中使用静态字段,或者在静态字段中调用非静态方法,问题将变得非常复杂。六、线程安全类当一个类已经很好的同步以保护它的数据时,这个类就称为“线程安全的”。即使是线程安全类,也应该特别小心,因为操作的线程是间仍然不一定安全。举个形象的例子,比如一个集合是线程安全的,有两个线程在操作同一个集合对象,当第一个线程查询集合非空后,删除集合中所有元素的时候。第二个线程也来执行与第一个线程相同的操作,也许在第一个线程查询后,第二个线程也查询出集合非空

10、,但是当第一个执行清除后,第二个再执行删除显然是不对的,因为此时集合已经为空了。看个代码:publicclassNameList privateList nameList = Collections.synchronizedList(newLinkedList();publicvoidadd(String name) nameList.add(name);publicString removeFirst() if(nameList.size() 0) return(String) nameList.remove(0);elsereturnnull;publicclassTest publics

11、taticvoidmain(String args) finalNameList nl =newNameList();nl.add(aaa);classNameDropperextendsThreadpublicvoidrun()String name = nl.removeFirst();System.out.println(name);Thread t1 =newNameDropper();Thread t2 =newNameDropper();t1.start();t2.start();虽然集合对象 private List nameList = Collections.synchron

12、izedList(new LinkedList();是同步的,但是程序还不是线程安全的。出现这种事件的原因是,上例中一个线程操作列表过程中无法阻止另外一个线程对列表的其他操作。解决上面问题的办法是,在操作集合对象的NameList上面做一个同步。改写后的代码如下:publicclassNameList privateList nameList = Collections.synchronizedList(newLinkedList();publicsynchronizedvoidadd(String name) nameList.add(name);publicsynchronizedStri

13、ng removeFirst() if(nameList.size() 0) return(String) nameList.remove(0);elsereturnnull;这样,当一个线程访问其中一个同步方法时,其他线程只有等待。八、线程同步小结1、线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。2、线程同步方法是通过锁来实现,每个对象都有切仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获得锁,当在一个

14、同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。4、对于同步,要时刻清醒在哪个对象上同步,这是关键。5、编写线程安全的类,需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断,对“原子”操作做出分析,并保证原子操作期间别的线程无法访问竞争资源。6、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。7、死锁是线程间相互等待锁锁造成的,在实际中发生的概率非常的小。真让你写个死锁程序,不一定好使,呵呵。但是,一旦程序发生死锁,程序将死掉。Java线程:线程的交互一、 线程交互的基础知识二、 void notify() 唤醒在此对象监视器上等待的单个线程。void notif

15、yAll() 唤醒在此对象监视器上等待的所有线程。void wait() 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。当然,wait()还有另外两个重载方法:void wait(long timeout) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。void wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过

16、某个实际时间量。关于等待/通知,要记住的关键点是:必须从同步环境内调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。wait()、notify()、notifyAll()都是Object的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知)。线程通过执行对象上的wait()方法获得这个等待列表。从那时候起,它不再执行任何其他指令,直到调用对象的notify()方法为止。如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)继续执行千万注意:当在对象上调用wait()方法时

17、,执行该代码的线程立即放弃它在对象上的锁。然而调用notify()时,并不意味着这时线程会放弃其锁。如果线程荣然在完成同步代码,则线程在移出之前不会放弃锁。因此,只要调用notify()并不意味着这时该锁变得可用Java线程:线程的调度-休眠Java线程调度是Java多线程的核心,只有良好的调度,才能充分发挥系统的性能,提高程序的执行效率。这里要明确的一点,不管程序员怎么编写调度,只能最大限度的影响线程执行的次序,而不能做到精准控制。线程休眠的目的是使线程让出CPU的最简单的做法之一,线程休眠时候,会将CPU资源交给其他线程,以便能轮换执行,当休眠一定时间后,线程会苏醒,进入准备状态等待执行。

18、线程休眠的方法是Thread.sleep(long millis) 和Thread.sleep(long millis, int nanos) ,均为静态方法,那调用sleep休眠的哪个线程呢?简单说,哪个线程调用sleep,就休眠哪个线程。在使用synchronized关键字时候,应该尽可能避免在synchronized方法或synchronized块中使用sleep或者yield方法,因为synchronized程序块占有着对象锁,你休息那么其他的线程只能一边等着你醒来执行完了才能执行。不但严重影响效率,也不合逻辑。同样,在同步程序块内调用yeild方法让出CPU资源也没有意义,因为你占用

19、着锁,其他互斥线程还是无法访问同步程序块。当然与同步程序块无关的线程可以获得更多的执行时间。对于本例,要说明的是当发现不能满足生产或者消费条件的时候,调用对象的wait方法,wait方法的作用是释放当前线程的所获得的锁,并调用对象的notifyAll() 方法,通知(唤醒)该对象上其他等待线程,使得其继续执行。这样,整个生产者、消费者线程得以正确的协作执行。notifyAll() 方法,起到的是一个通知作用,不释放锁,也不获取锁。只是告诉该对象上等待的线程“可以竞争执行了,都醒来去执行吧”。Java线程:volatile关键字Java 语言包含两种内在的同步机制:同步块(或方法)和 volat

20、ile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。目前为止,您应该了解了 volatile 的功能还不足以实现计数器。因为+x实际上是三种操作(读、添加、存储)的简单组合,如果多个线程凑巧试图同时对 volatile 计数器执行增量操作,那么它的更新值有可能会丢失。然而,如果读操作远远超过写操作,您可以结合使用内部锁和 volatile 变量来减少公共代码路径的开销。清单 6 中显示的线程安全的计数器使用synchronized确保增量操作是原子的,并使用volatile保证当前结果的可见

21、性。如果更新不频繁的话,该方法可实现更好的性能,因为读路径的开销仅仅涉及 volatile 读操作,这通常要优于一个无竞争的锁获取的开销。清单 6. 结合使用 volatile 和 synchronized 实现 “开销较低的读写锁” ThreadSafepublic class CheesyCounter / Employs the cheap read-write lock trick / All mutative operations MUST be done with the this lock held GuardedBy(this) private volatile int value; public int getValue() return value; public synchronized int increment() return value+; 10 / 10

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!