非线程安全问题

“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程问题”。也即是说,方法中的变量永远是线程安全的。

如果多个线程共同访问1个对象中的实例变量,则可能线程不安全。下面以实例说明

 public class HasSelfNum {
private int num = 0;
public void add(String name) {
try {
if (name.equals("a")) {
num = 100;
System.out.println("a over");
Thread.sleep(1000);
} else {
num = 200;
System.out.println("b over");
}
System.out.println(name+" "+num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
 public class ThreadA extends Thread{
private HasSelfNum hasSelfNum; public ThreadA(HasSelfNum hasSelfNum) {
this.hasSelfNum = hasSelfNum;
} @Override
public void run() {
super.run();
hasSelfNum.add("a");
}
}
 public class ThreadB extends Thread{
private HasSelfNum hasSelfNum; public ThreadB(HasSelfNum hasSelfNum) {
this.hasSelfNum = hasSelfNum;
} @Override
public void run() {
super.run();
hasSelfNum.add("b");
}
}
 public class Main {
public static void main(String[] args) {
HasSelfNum hasSelfNum = new HasSelfNum();
ThreadA threadA = new ThreadA(hasSelfNum);
ThreadB threadB = new ThreadB(hasSelfNum); threadA.start();
threadB.start();
}
}

Result

 a over
b over
b 200
a 200
非线程安全!
如何处理?
在add方法上加上关键字 synchronized
synchronized public void add(String name)
Result
 a over
a 100
b over
b 200

线程安全,同步访问add()方法

如果是多个对象的情况?

将上面的Main.java进行修改

 public class Main {
public static void main(String[] args) {
HasSelfNum hasSelfNum = new HasSelfNum();
HasSelfNum hasSelfNum2 = new HasSelfNum(); //两个对象 ThreadA threadA = new ThreadA(hasSelfNum);
ThreadB threadB = new ThreadB(hasSelfNum2); threadA.start();
threadB.start();
}
}

Result

 a over
b over
b 200
a 100
两个线程分别访问同一个类的不同实例的相同同步方法,产生了两个锁,运行的结果是异步的。
由此可以看出,关键字synchronized取得的锁是对象锁

若类中既有synchronized类型方法又有非synchronized类型方法

 public class MyObject {
synchronized public void methodA(){
try {
System.out.println(Thread.currentThread().getName()+" begin");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public void methodB(){
try {
System.out.println(Thread.currentThread().getName()+" begin");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
 public class ThreadA extends Thread{
MyObject myObject;
public ThreadA(MyObject myObject) {
this.myObject = myObject;
} @Override
public void run() {
super.run();
myObject.methodA();
}
}
 public class ThreadB extends Thread{
MyObject myObject;
public ThreadB(MyObject myObject) {
this.myObject = myObject;
} @Override
public void run() {
super.run();
myObject.methodB();
}
}
 public class Main {
public static void main(String[] args) {
MyObject myObject = new MyObject(); ThreadA threadA = new ThreadA(myObject);
ThreadB threadB = new ThreadB(myObject);
threadA.setName("A");
threadB.setName("B"); threadA.start();
threadB.start();
}
}

Result

 A begin
B begin
B end
A end
线程A持有myObject对象锁,但线程B仍可以异步调用非synchronized类型方法
当在methodB方法前也加上synchronized关键字时
Result
 A begin
A end
B begin
B end

线程A、B以同步的方式执行对象中的两方法

synchronized同步代码块

当synchronized修饰的方法里有个耗时很长的代码时,效率是很低的。同步代码块分为:
1.synchronized(this)
在方法中不在同步代码块中的代码异步执行,而在其中的代码同步执行
同个对象中的synchronized(this)使用的对象监视器是同一个,也就是说,当一个线程访问某个synchronized(this)代码块里面的方法时,其他线程访问其他synchronized(this)块里面的方法是会被阻塞的。另外synchronized(this)使用的监视器和syncheronized 修饰方法一致是当前对象,也会阻塞synchronized修饰的方法。
2.synchronized(obj) 非this
多个线程同时访问时只能阻塞synchronized(obj)的代码块。
同时如果锁是同一个myObject对象,还是会阻塞的
 public class MyObject {
synchronized public void methodA() {
try {
System.out.println(Thread.currentThread().getName() + " begin");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void methodB(MyObject myObject) {
synchronized (myObject) {
try {
System.out.println(Thread.currentThread().getName() + " begin");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
 public class ThreadA extends Thread{
MyObject myObject;
public ThreadA(MyObject myObject) {
this.myObject = myObject;
} @Override
public void run() {
super.run();
myObject.methodA();
}
}
 public class ThreadB extends Thread{
MyObject myObject;
public ThreadB(MyObject myObject) {
this.myObject = myObject;
} @Override
public void run() {
super.run();
myObject.methodB(myObject);
}
}
 public class Main {
public static void main(String[] args) {
MyObject myObject = new MyObject(); ThreadA threadA = new ThreadA(myObject);
ThreadB threadB = new ThreadB(myObject);
threadA.setName("A");
threadB.setName("B"); threadB.start();
threadA.start();
}
}

Result

 B begin
B end
A begin
A end

《Java多线程编程核心技术》学习

Java多线程synchronized同步的更多相关文章

  1. Java 多线程 —— synchronized关键字

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  2. Java多线程的同步控制记录

    Java多线程的同步控制记录 一.重入锁 重入锁完全可以代替 synchronized 关键字.在JDK 1.5 早期版本,重入锁的性能优于 synchronized.JDK 1.6 开始,对于 sy ...

  3. Java多线程之同步集合和并发集合

    Java多线程之同步集合和并发集合 不管是同步集合还是并发集合他们都支持线程安全,他们之间主要的区别体现在性能和可扩展性,还有他们如何实现的线程安全. 同步集合类 Hashtable Vector 同 ...

  4. Java多线程编程(同步、死锁、生产消费者问题)

    Java多线程编程(同步.死锁.生产消费): 关于线程同步以及死锁问题: 线程同步概念:是指若干个线程对象并行进行资源的访问时实现的资源处理保护操作: 线程死锁概念:是指两个线程都在等待对方先完成,造 ...

  5. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

  6. JAVA多线程synchronized详解

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 当两个并发线程访问同一个对象object中的这个synchronized(this)同 ...

  7. 转载:浅谈Java多线程的同步问题【很好我就留下来,多分共享】

    转载:http://www.cnblogs.com/phinecos/archive/2010/03/13/1684877.html#undefined 多线程的同步依靠的是对象锁机制,synchro ...

  8. 浅谈Java多线程的同步问题 【转】

    多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问. 下面以一个简单的实例来进行对比分析.实例要完成的工作非常简单,就是创建10个线程,每个线 ...

  9. Java多线程 - 线程同步

    多线程操作同一个对象时,容易引发线程安全问题.为了解决线程安全问题,Java多线程引入了同步监视器. 同步代码块 同步代码块语法格式如下: synchronized(obj){ //此处的代码即为同步 ...

随机推荐

  1. jQuery in action 3rd - Working with properties, attributes, and data

    properties properties 是 JavaScript 对象内在的属性,可以进行动态创建,修改等操作. attributes 指的是 DOM 元素标记出来的属性,不是实例对象的属性. 例 ...

  2. Java:switch语句例子

    1.输入一个名次,第1-4名,分别称为冠军.亚军.季军.殿军,5名及5名以上,称为其他名次. import java.util.Scanner; public class switch1 { publ ...

  3. Python 3 —— 控制语句

    控制语句 1.if if <s>: ... elif <s>: ... else: ... 2 for for e in list .. if <s> break; ...

  4. [UCSD白板题] Least Common Multiple

    Problem Introduction The least common multiple of two positive integers \(a\) and \(b\) is the least ...

  5. 在Web应用中接入微信支付的流程之极简清晰版

    在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...

  6. zmq学习笔记

    1 zmq_socket(3) Manual Page 1.1 一个socket可连接多个对端socket: 通过使用多个zmq_connect() 1.2 一个socket可绑定到多个地址上接受连接 ...

  7. 使用Xcode6创建EmptyProject

    多年不写文章,今天突然准备好好写一些博客,以记录自己在编程这条道路上的成长,与所学所悟.提起笔来,才发现,自己的语言之匮乏,思虑再三,始觉不顺.也罢,从头开始慢慢训练吧. 自Xcode6更新之后,默认 ...

  8. 00.PHP学习建议

    各位师弟师妹,大家好~PHP不是我们专业的本该有的方向.我不知道大家为什么来学习这门语言,也许是自己了解之后喜欢这门语言(我想这种可能在我们专业是挺少的),也许是听守中哥说这门语言简单好学,为了躲避学 ...

  9. LINUX btmp 日志(lastb 命令)

    Linux下/var/log/btmp文件: 今天查看了一下服务器,发现/var/log/btmp日志文件比较大,搜索一下,此文件是记录错误登录的日志,就是说有很多人试图使用密码字典登录ssh服务,此 ...

  10. Remote Desktop Connection Manager (RDCMan)

    当前最新版本是 v2.7. 通过这款软件,我们便可以轻松的管理和访问数个RDP.左边的列表中我们可以创建总的分区列表(即 RDCMan Group),该列表保存采用的是RDG扩展名,使用时通过&quo ...