Java线程:同步
2015-12-21 21:59
113 查看
[b]一 同步的概念[/b]
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。
例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据。
[b]MyRunnable.java[/b]
View Code
结果为:
但是如果把同步关键字synchronized去掉,结果为:
显然是错误的,多个线程并发访问了竞争资源u,并对u的属性做了修改。可见同步的重要性。
[b]2、同步块[/b]
有时候,同步块比同步方法有更好的效果。在上个例子的基础上对oper方法做了改变,由同步方法改为同步块模式。
BankTest.java
结果和上例是一样的。具体的变化思想为:
注意:
在使用synchronized时,应该避免在synchronized方法或synchronized块中使用sleep或yield方法。因为synchronized程序块占用着对象锁,你休息那么其他线程只能等待。这样效率不高。同样,在同步程序块内调用yield方法让出CPU资源也没有意义,因为你占用着锁,其他资源无法访问。
[b]二、静态方法同步[/b]
要同步静态方法,需要一个用整个类对象的锁,这个对象就是这个类(xxx.class),如:
[b]三、何时需要同步[/b]
1、多个线程同时访问互斥(可交换)数据时,应该同步保护数据,确保两个线程不会同时更改它。
2、非静态字段中可更改的数据,通常用非静态方法访问。
3、静态字段中可更改的数据,用静态方法访问。
[b]四、总结[/b]
1、线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。
2、线程同步方法是通过锁来实现,每个对象都仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程无法再访问该对象的其他同步方法。
3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁不干预。一个线程获得锁,当在一个同步方法中访问另外对象的同步方法时,会获取两个对象的锁。
4、对于同步,要时刻清醒哪个对象上同步,这是关键。
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。
例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据。
[b]MyRunnable.java[/b]
package Thread; public class BankTest { public static void main(String[] args){ User u=new User("小二",100); MyThread t1=new MyThread("线程1",u,20); MyThread t2=new MyThread("线程2",u,-60); MyThread t3=new MyThread("线程3",u,-80); MyThread t4=new MyThread("线程4",u,-30); MyThread t5=new MyThread("线程5",u,32); MyThread t6=new MyThread("线程6",u,21); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); } } class MyThread extends Thread{ private User u; private int y=0; MyThread(String name,User u,int y){ super(name); this.u=u; this.y=y; } public void run(){ u.oper(y); } } class User{ private String code; private int cash; User(String code,int cash){ this.code=code; this.cash=cash; } public String getCode(){ return code; } /** * 业务方法 * @param x 添加x万元 * */ public synchronized void oper(int x){ try{ Thread.sleep(10L); this.cash+=x; System.out.println(Thread.currentThread().getName()+"运行结果,增加"+x+",当前余额为:"+cash); Thread.sleep(10L); } catch(InterruptedException e){ e.printStackTrace(); } } public String toString(){ return "User{" + "code=" + code + ",cash=" + cash +'}'; } }
View Code
结果为:
线程1运行结果,增加20,当前余额为:120 线程2运行结果,增加-60,当前余额为:60 线程6运行结果,增加21,当前余额为:81 线程5运行结果,增加32,当前余额为:113 线程4运行结果,增加-30,当前余额为:83 线程3运行结果,增加-80,当前余额为:3
但是如果把同步关键字synchronized去掉,结果为:
线程2运行结果,增加-60,当前余额为:60 线程6运行结果,增加21,当前余额为:1 线程4运行结果,增加-30,当前余额为:3 线程5运行结果,增加32,当前余额为:3 线程1运行结果,增加20,当前余额为:60 线程3运行结果,增加-80,当前余额为:-20
显然是错误的,多个线程并发访问了竞争资源u,并对u的属性做了修改。可见同步的重要性。
[b]2、同步块[/b]
有时候,同步块比同步方法有更好的效果。在上个例子的基础上对oper方法做了改变,由同步方法改为同步块模式。
BankTest.java
public void oper(int x){ try{ Thread.sleep(10L); synchronized(this){ this.cash+=x; System.out.println(Thread.currentThread().getName()+"运行结果,增加"+x+",当前余额为:"+cash); } Thread.sleep(10L); } catch(InterruptedException e){ e.printStackTrace(); } }
结果和上例是一样的。具体的变化思想为:
1 public syncronized int getX(){ 2 return x++; //同步方法 3 } 4 与 5 public int getX(){ 6 synchronized(this){ 7 return x;//非同步方法 8 } 9 }
注意:
在使用synchronized时,应该避免在synchronized方法或synchronized块中使用sleep或yield方法。因为synchronized程序块占用着对象锁,你休息那么其他线程只能等待。这样效率不高。同样,在同步程序块内调用yield方法让出CPU资源也没有意义,因为你占用着锁,其他资源无法访问。
[b]二、静态方法同步[/b]
要同步静态方法,需要一个用整个类对象的锁,这个对象就是这个类(xxx.class),如:
1 public static synchronized int setName(String name){ 2 xxx.name=name; 3 } 4 等价于 5 public static int setName(){ 6 synchronized(xxx.class){ 7 xxx.name=name; 8 } 9 }
[b]三、何时需要同步[/b]
1、多个线程同时访问互斥(可交换)数据时,应该同步保护数据,确保两个线程不会同时更改它。
2、非静态字段中可更改的数据,通常用非静态方法访问。
3、静态字段中可更改的数据,用静态方法访问。
[b]四、总结[/b]
1、线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。
2、线程同步方法是通过锁来实现,每个对象都仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程无法再访问该对象的其他同步方法。
3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁不干预。一个线程获得锁,当在一个同步方法中访问另外对象的同步方法时,会获取两个对象的锁。
4、对于同步,要时刻清醒哪个对象上同步,这是关键。
相关文章推荐
- java注释
- 从头认识java-13.14 捕捉通配符替代的类型参数
- Java实现高斯模糊算法处理图像
- 【java学习笔记s】继承
- java泛型
- JAVA概念大全
- Java Font 居中 反锯齿效果
- android maven eclipse里面新建mavenprojectThe desired archetype does not exist
- java反射
- 从头认识java-13.13 无界通配符
- 【菜鸟学Java】7:JSP的基本语法
- Java中点击按钮返回上一页
- Eclipse调试Bug的七种常用技巧
- java中“==”和equal区别
- JAVA NIO之浅谈内存映射文件原理与DirectMemory
- 【转】在Eclipse中使用JUnit4进行单元测试(高级篇)
- 【转】 在Eclipse中使用JUnit4进行单元测试(中级篇)
- java并发编程学习之脏读代码示例及处理
- 解决"STSong-Light' with 'UniGB-UCS2-H' is not recognized"问题
- Java Day1