非线程安全问题

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

如果多个线程共同访问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. Oracle 服务手动启动关闭

    在windows7中安装完Oracle11g之后会出现一下七种服务:可通过运行->services.msc查看. 其中各个服务名称中的ORCL或orcl为SID即System IDentifie ...

  2. jquery 监听input输入值事件

    <html> <head> <title></title> <script type="text/javascript" sr ...

  3. Codeforces Zip-line 650D 345Div1D(LIS)

    传送门 大意:给出一个序列,求修改一个数过后的最长上升子序列. 思路:可以用主席树在线搞,也可以用树状数组离线搞,明显后者好写得多.我们首先读取所有的询问,然后就把询问绑在给出的位置,然后我们正向做一 ...

  4. Oozie命令行常用命令汇总[转]

    Oozie命令行常用命令汇总 有时候脚本跑多了就不愿意在OozieWeb端去看脚本的运行情况了.还好Oozie提供了很多命令行命令.能通过命令行直接检索自己想看到的脚本信息.在这里简单进行一下总结.一 ...

  5. FMX下Edit只能输入数字

    procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState) ...

  6. Mysql运行SQL文件 错误Incorrect table definition;there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

    问题描述 想从服务器上DOWN下数据库.操作:先把数据库转存为SQL文件,然后在本地利用navicate运行SQL文件,出现错误信息: Incorrect table definition;there ...

  7. 字符串匹配的Boyer-Moore算法

    作者: 阮一峰    http://www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.html 上一篇文章,我介绍 ...

  8. 在docker里部署网络服务

    之前试着玩玩docker有一阵子了,今天算是头一回正式在docker里部署网络服务. 本来想和lxc差不多的东西那自然是手到擒来,没想到还是改了很多. 第一个遇到的问题是,远程连到docker宿主机干 ...

  9. \(\S1\) 描述性统计

    在认识客观世界的过程中,统计学的思想和方法经常起着不可替代的作用.在许多工程及自然科学的专业领域中,包括可靠性分析.质量控制.生物信息.脑科学.心理分析.经济分析.金融风险管理.社会科学推断.行为科学 ...

  10. javascript opacity兼容性随笔

    一.CSS兼容代码 .transparent { filter:alpha(opacity=50); /* IE */ -moz-opacity:0.5; /* FireFox old version ...