




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
使用synchronized实现多线程同步(转)2008-11-06 16:25 笔注:这篇文章来自网络,比较详细描述了线程同步的一些细节信息,但是个人觉得对synchronized用法的说明,还不完整,比如并没有详细说明synchronized共享方法的用法等等。 使用synchronized关键字,多线程程序的运行结果将变得可以控制。synchronized关键字用于保护共享数据。请大家注意共享数据,你一定要分清哪些数据是共享数据, JAVA是面向对象的程序设计语言,所以初学者在编写多线程程序时,容易分不清哪些数据是共享数据。请看下面的例子:public class ThreadTest implements Runnable public synchronized void run() for(int i=0;i10;i+) System.out.print( + i);public static void main(String args) Runnable r1 = new ThreadTest();Runnable r2 = new ThreadTest();Thread t1 = new Thread(r1);Thread t2 = new Thread(r2);t1.start();t2.start(); 在这个程序中,run()被加上了synchronized关键字。在main方法中创建了两个线程。你可能会认为此程序的运行结果一定为:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。但你错了!这个程序中synchronized关键字保护的不是共享数据(其实在这个程序中synchronized关键字没有起到任何作用,此程序 的运行结果是不可预先确定的)。这个程序中的t1,t2是两个对象(r1,r2)的线程。JAVA是面向对象的程序设计语言,不同的对象的数据是不同的, r1,r2有各自的run()方法,而synchronized使同一个对象的多个线程,在某个时刻只有其中的一个线程可以访问这个对象的 synchronized数据。每个对象都有一个锁标志,当这个对象的一个线程访问这个对象的某个synchronized数据时,这个对象的所有被 synchronized修饰的数据将被上锁(因为锁标志被当前线程拿走了),只有当前线程访问完它要访问的synchronized数据时,当前线 程才会释放锁标志,这样同一个对象的其它线程才有机会访问synchronized数据。public class ThreadTest implements Runnable public synchronized void run() for(int i=0;i10;i+) System.out.print( + i);public static void main(String args) Runnable r = new ThreadTest();Thread t1 = new Thread(r);Thread t2 = new Thread(r);t1.start();t2.start(); 如果你运行1000次这个程序,它的输出结果也一定每次都是:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。因为这里的synchronized保护的是共享数据。t1,t2是同一个对象(r)的两个线程,当其中的一个线程(例如:t1)开始执行run() 方法时,由于run()受synchronized保护,所以同一个对象的其他线程(t2)无法访问synchronized方法(run方法)。只有当 t1执行完后t2才有机会执行。synchronized(this) for(int i=0;i10;i+) System.out.print( + i);下面是关于线程同步的一些知识:(1)对一个类的instance method,当此方法被一个线程调用时,其他线程不能再通过同一个对象调用此方法(可以通过这个类的另一个对象来调用这个方法。(2)对一个类的static method,则当一个线程通过类对象调用此方法时,其他线程不能再通过类对象调用此方法。由于类对象在类加载时由虚拟机创建,只有一个,所以同一时刻此方法只能被一个线程调用。(3)在servlet程序中,容器只实例化一个servlet对象,多个用户访问的是同一个servlet对象,因此对servlet的方法加同步修饰,可以防止多个用户同时调用一个方法,避免共享冲突。(4)创建多线程程序时,在子线程中通过一个对象调用一个类的instance方法时,应该在主线程创建这个对象,将对象的引用通过子线程的构造函数或其他接口方法传入子线程,供子线程使用。(5) 多线程有两种实现方法,分别是继承Thread类与实现Runnable接口;线程同步的实现方面有两种,分别是synchronized,wait与notify(6)启动一个线程是用run()还是start()呢?启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。(7)sleep() 和 wait() 的区别:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。wait()方法被调用时会解除锁定,但是我们能使用它的地方只是在一个同步的方法或代码块内。wait()/notify():调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用 任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。(8) 同步和异步的区别及调用:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。(9) 当一个线程进入一个对象的一个synchronized方法后,其它线程不能进入此对象的其它方法,因为一个对象的一个synchronized方法只能由一个线程访问。(10) 多线程中有主内存和工作内存之分, 在JVM中,有一个主内存,专门负责所有线程共享数据;而每个线程都有他自己私有的工作内存, 主内存和工作内存分贝在JVM的stack区和heap区。(11) 线程的状态有Ready, Running, Sleeping, Blocked, 和 Waiting的几个状态,Ready 表示线程正在等待CPU分配允许运行的时间。(12) 当一个线程进入一个对象的一个synchronized方法后当一个线程进入一个对象的一个synchronized方法后线程运行次序并不是按照我们创建他们时的顺序来运行的,CPU处理线程的顺序是不确定的,如果需要确定,那么必须手工介入,使用setPriority()方法设置优先级。(13) 我们无从知道一个线程什么时候运行,两个或多个线程在访问同一个资源时,需要synchronized(14) 每个线程会注册自己,实际某处存在着对它的引用,因此,垃圾回收机制对它就“束手无策”了。(15) 守护线程 ( Daemon线程 )Daemon线程区别一般线程之处是:主程序一旦结束,Daemon线程就会结束。守护线程是一类特殊的线程,它和普通线程的区别在于它并不是应用程序的核心部分,当一个应用程序的所有非守护线程终止运行时,即使仍然有守护线程在运行,应用程序也将终止,反之,只要有一个非守护线程在运行,应用程序就不会终止。守护线程一般被用于在后台为其它线程提供服务。可以通过调用方法 isDaemon() 来判断一个线程是否是守护线程,也可以调用setDaemon() 来将一个线程设为守护线程。(16) 一个对象中的所有synchronized方法都共享一把锁,这把锁能够防止多个方法对通用内存同时进行的写操作。 synchronized static方法可在一个类范围内被相互间锁定起来。(17) 对于访问某个关键共享资源的所有方法,都必须把它们设为synchronized,否则就不能正常工作。(18) 假设已知一个方法不会造成冲突,最明智的方法是不要使用synchronized,能提高些性能。(19) 如果一个同步方法修改了一个变量,而我们的方法要用到这个变量(可能是只读),最好将自己的这个方法也设为 synchronized。(20) synchronized不能继承, 父类的方法是synchronized,那么其子类重载方法中就不会继承“同步”。(21) 线程堵塞Blocked有几个原因造成:1. 线程在等候一些IO操作2. 线程试图调用另外一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。(22) 使用yield()会自动放弃CPU,有时比sleep更能提升性能。(23) 通过制造缩小同步范围,尽可能的实现代码块同步,wait(毫秒数)可在指定的毫秒数可退出wait;对于wait()需要被notisfy()或notifyAll()踢醒。(24) synchronized带来的问题除性能有所下降外,最大的缺点是会带来死锁DeadLock,只有通过谨慎设计来防止死锁,其他毫无办法,这也是线程难以驯服的一个原因。不要再使用stop() suspend() resume()和destory()方法(25) 在大量线程被堵塞时,最高优先级的线程先运行。但是不表示低级别线程不会运行,运行概率小而已。(26) 线程组的主要优点是:使用单个命令可完成对整个线程组的操作。很少需要用到线程组。(27) 以下几个方面提升多线程的性能:1.检查所有可能Block的地方,尽可能的多的使用sleep或yield()以及wait();2.尽可能延长sleep(毫秒数)的时间;3.运行的线程不用超过100个,不能太多;4.不同平台linux或windows以及不同JVM运行性能差别很大。笔注:本文来源:/godmoves/blog/item/a80198548a2ca01f3b293534.html。本文对synchronized讲解的比较全面,但却有点笼统,如果可以更详细一点,会更利于我这种菜鸟级的学习。 总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。在进一步阐述之前,我们需要明确几点:A无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁而且同步方法很可能还会被其他线程的对象访问。B每个对象只有一个锁(lock)与之相关联。C实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。接着来讨论synchronized用到不同地方对代码产生的影响:假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。1 把synchronized当作函数修饰符时,示例代码如下:Public synchronized void methodAAA()/.这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。上边的示例代码等同于如下代码:public void methodAAA()synchronized (this) / (1) /.(1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(2同步块,示例代码如下: public void method3(SomeObject so) synchronized(so) /.这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:class Foo implements Runnable private byte lock = new byte0; / 特殊的instance变量 Public void methodA() synchronized(lock) / /.注:零长度的byte数组对象创建起来将比任何对象都经济查看编译后的字节码:生成零长度的byte对象只需3条操作码,而Object lock = new Object()则需要7行操作码。3将synchronized作用于static 函数,示例代码如下: Class Foopublic synchronized static void methodAAA() / 同步的static 函数/.public void methodBBB() synchronized(Foo.class) / class literal(类名称字面常量) 代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 婚后共同投资影视制作公司债务分摊及权益共享协议
- 红筹模式股权投资并购与风险控制管理合同
- 《MRI高效成像技术》课件
- 母婴护理专业培训与市场推广合作框架
- 国企混改股权合作及产业链优化与整合协议
- 食管裂孔疝麻醉管理
- 《疾病抗药性机制》课件
- 《深入掌握LINUX:课件引导式学习》
- 《慢性肉芽肿性疾病的诊断与治疗》课件
- 延期支付绩效薪酬培训
- 耐药菌耐药性监测策略-全面剖析
- 北京市通州区2025年初中学业水平模拟考试(一模)英语试卷(含答案)
- 手术中大出血抢救流程
- 2025重庆武工工业技术研究院有限公司招聘15人笔试参考题库附带答案详解
- 光伏电站面试题库及答案
- 2024年泉州实验中学初一新生入学考试数学试卷
- 车间技能矩阵管理制度
- 陶艺店管理制度
- 2025-2030中国储能电站行业市场深度分析及前景趋势与投资研究报告
- 2025年标准租房合同范本
- 三元空间下个人化IP综艺《灿烂的花园》叙事与价值研究
评论
0/150
提交评论