非线程安全问题

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

如果多个线程共同访问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. out与ref的区别

    out与ref的区别  前者传参时不必初始化,后者需要初始化 int a,b; public void fName(out int a,out int b); fName(out a , out b) ...

  2. 从up6-down2升级到down3

    概述: 添加存储过程down_f_process.sql,down_f_del.sql 更新DnFile.updateProcess,DnFile.Delete 更新down.js 更新down.fo ...

  3. 看来System.dll是没法剔除依赖了

    今天花了半天时间将System.Xml换成了Mono.Xml 想干掉System.dll发现不行了,System.Net以及System.IO都在这下面,还有protobuf-net也逃不掉这个 算啦 ...

  4. 《Linux内核分析》之第四章读书笔记

    4.1多任务 多任务操作系统:同时并发地交互执行多个进程的操作系统 多任务操作系统会使多个进程处于堵塞或者睡眠状态.这些任务尽管位于内存,但是并不处于可运行状态.这些进程利用内核堵塞自己,直到某一事件 ...

  5. 数据库、数据表的创建SP2

      本人前一个版本的数据库.数据表的创建由于不是很详细,于是通过细心的修订,已经修复了很多Bug,希望这篇文章能够给大家一些帮助 --代表注释,相当于C#里的// --切换到master数据库,目的是 ...

  6. 第8章 NAND FLASH控制器

    8.1 NAND Flash介绍和NAND Flash控制器使用 NAND Flash在嵌入式系统中的地位与PC上的硬盘类似 NAND Flash在掉电后仍可保存 8.1.1 Flash介绍 有NOR ...

  7. AndroidManifest.xml中<activity></activity>相关属性说明

    虽说,从事android开发有一定时间了,对于Activity大家也都不陌生,但是具体的对于Activity中相关属性的含义有必要做一个系统的总结: intent-filteraction: 来指定响 ...

  8. Android中的IntentService

    首先说下,其他概念:Android中的本地服务与远程服务是什么? 本地服务:LocalService 应用程序内部------startService远程服务:RemoteService androi ...

  9. 多线程NSInvocationOperation(NSOperationQueue)的基本用法

        #import "ViewController.h" @interface ViewController () @end @implementation ViewContr ...

  10. Getting Started with WebRTC [note]

    Getting Started with WebRTC 原文 RTCPeerConnection 1.caller和callee互相发现彼此 2.并且交换capabilities信息 3.初始化ses ...