非线程安全问题

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

如果多个线程共同访问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. myeclipse使用maven插件进行maven install时报错check $m2_home environment variable and mvn script match

    check $m2_home environment variable and mvn script match 分类: maven2015-09-01 18:06 842人阅读 评论(0) 收藏 举 ...

  2. UI拼图导出脚本,兼容cegui的ImageSet格式

    该脚本用于photoshop,美术可以先用photoshop拼接图片,在加载该脚本导出xml格式的文件,该文件记录了每个小的图片坐标信息 // Copyright 2002-2003. Adobe S ...

  3. JavaScript 基础第五天

    一.引言 前面我们讨论了函数的一些基本概念,因为函数在任何一门语言之中都是很重要所以还是要好好学.昨天打开博客的时候看到有人私信我的JavaScript写错了,我定睛一看果然写错了.对此我表示很抱歉, ...

  4. python 库安装

    用到再更新. #Windows 一 exe 安装包 http://www.lfd.uci.edu/~gohlke/pythonlibs/#scikit-learn 二 setup.py cmd 进入目 ...

  5. Constructing Roads In JGShining's Kingdom(HDU1025)(LCS序列的变行)

    Constructing Roads In JGShining's Kingdom  HDU1025 题目主要理解要用LCS进行求解! 并且一般的求法会超时!!要用二分!!! 最后蛋疼的是输出格式的注 ...

  6. java分割字符串

    经验分享: 1.分隔符为“.”(无输出),“|”(不能得到正确结果)转义字符时,“*”,“+”时出错抛出异常,都必须在前面加必须得加"\\",如split(\\|); 2.如果用& ...

  7. poj 1806 分块模拟

    Manhattan 2025 Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1318   Accepted: 703 Des ...

  8. css使一行文字竖向排列

    .tnt { margin:0 auto;width:20px;line-height:24px;} <div class="tnt" > <asp:Label ...

  9. 《与mysql零距离接触》视屏学习笔记

    1.数据表的增删改查操作(crud): 对于表: 增:create  table  XXXX 删:drop table XXXX 改:alter table XXXX rename to XXXX 查 ...

  10. [转载]sql语句练习50题

    Student(Sid,Sname,Sage,Ssex) 学生表 Course(Cid,Cname,Tid) 课程表 SC(Sid,Cid,score) 成绩表 Teacher(Tid,Tname) ...