synchronized是用来解决多线程情况下的线程安全问题的,它可以修饰方法也可以修饰语句块 ,

那么什么情况下是线程安全和线程不安全呢 ?

方法内的变量是线程安全的 , 类的实例变量是非线程安全的

首先来看一个非线程安全的例子

public class HasSefPrivateNum {
private int num;
public void addNum(String userName) throws InterruptedException{
if("a".equals(userName)){
num=100;
System.out.println("a set over");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over");
}
System.out.println("num="+num);
}
} public class ThreadA extends Thread {
private HasSefPrivateNum numRef;
public ThreadA(HasSefPrivateNum numRef) {
this.numRef = numRef;
} @Override
public void run() {
super.run();
try {
numRef.addNum("a");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} public class ThreadB extends Thread {
private HasSefPrivateNum numRef;
public ThreadB(HasSefPrivateNum numRef) {
this.numRef = numRef;
} @Override
public void run() {
super.run();
try {
numRef.addNum("b");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} public class Main {
public static void main(String[] args) {
HasSefPrivateNum numRef = new HasSefPrivateNum();
ThreadA t1 = new ThreadA(numRef);
t1.start();
ThreadB t2 = new ThreadB(numRef);
t2.start();
}
}

结果如下,出现非线程安全的问题

a set over
b set over
num=200
num=200

此时synchronized派上用场了,只要在addNum方法上synchronized,就能避免非线程安全问题

public class HasSefPrivateNum {
private int num;
public synchronized void addNum(String userName) throws InterruptedException{
if("a".equals(userName)){
num=100;
System.out.println("a set over");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over");
}
System.out.println("num="+num);
}
}

结果如下:

a set over
num=100
b set over
num=200

那么synchronized是怎么实现同步的呢

1. synchronized用在实例方法上那么它是持有对象锁,而不是把一段代码或方法当作锁,所以必须使用同一个对象当作锁才能达到同步的效果;

2. synchronized用在静态方法上那么它是对当前java文件对应的class类持锁。

首先看下synchronized修饰实例方法

public class Main {
public static void main(String[] args) {
HasSefPrivateNum numRef1 = new HasSefPrivateNum();
HasSefPrivateNum numRef2 = new HasSefPrivateNum();
ThreadA t1 = new ThreadA(numRef1);
t1.start();
ThreadB t2 = new ThreadB(numRef2);
t2.start();
}
}

结果如下,没有发生同步,因为两个线程拥有两个不同对象的锁

a set over
b set over
num=200
num=100

synchronized解决脏读问题

public class PublicVar {
private String username="A";
private String password="AA";
public synchronized void setValue(String username,String password){
try {
this.username = username;
Thread.sleep(5000);
this.password = password;
System.out.println("setValue method thread name=" + Thread.currentThread().getName()
+"username:"+username+",password:"+password); } catch (InterruptedException e) {
e.printStackTrace();
}
}
public void getValue(){
System.out.println("getValue method thread name=" + Thread.currentThread().getName()
+"username:"+username+",password:"+password);
}
} public class ThreadA extends Thread {
private PublicVar publicVar;
public ThreadA(PublicVar publicVar) {
this.publicVar = publicVar;
}
@Override
public void run() {
super.run();
publicVar.setValue("B", "BB");
}
} public class Main {
public static void main(String[] args) throws InterruptedException {
PublicVar publicVar = new PublicVar();
ThreadA t1 = new ThreadA(publicVar);
t1.start();
Thread.sleep(2000);
publicVar.getValue();
}
}

结果如下,get方法出现脏读的情况,原因是getValue方法不是同步方法,只需将getValue方法变成同步方法后就可以解决这个问题

getValue method thread name=mainusername:B,password:AA
setValue method thread name=Thread-0username:B,password:BB

对同步方法总结:

1. synchronized方法是持有对象锁,对相同的对象的synchronized方法会进行同步执行

2. 对于同一个对象锁内不同的synchronized方法持有同一个锁,即A线程调用了synchronized方法X,那么其他线程就不能调用其他的synchronized方法,直到synchronized方法x执行完后,但是可以调用其他非synchronized方法

3.synchronized方法支持锁重入,自己可以再次获得自己的内部锁,即当一个线程获得synchronized方法执行权后,在该方法内能调用该对象其他synchronized方法,如果不能重入,将会造成死锁。

4. synchronized方法出现异常,锁自动释放。

5. synchronized方法不具有继承性

使用同步代码块实现同步

synchronized的另一种用法就是同步代码块,和synchronized方法相比,它有两个有点

1. 它可以只针对方法内需要同步的代码进行同步,缩小同步范围,提高效率。

2. 它可以在同一个类中针对不同对象进行同步,提高效率。

public class Task {
private String getData1;
private String getdate2; public void doLongTimeTask(){
try {
System.out.println("begin task");
Thread.sleep(3000);
String privateGetData1 = "返回值1 thread name="+Thread.currentThread().getName();
String privateGetData2 = "返回值2 thread name="+Thread.currentThread().getName(); synchronized (this) {
getData1 = privateGetData1;
getdate2 = privateGetData2;
}
System.out.println(getData1);
System.out.println(getdate2);
System.out.println("end task");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public class ThreadA extends Thread {
private Task task;
public ThreadA(Task task) {
this.task = task;
}
@Override
public void run() {
super.run();
task.doLongTimeTask();
}
} public class ThreadB extends Thread {
private Task task;
public ThreadB(Task task) {
this.task = task;
}
@Override
public void run() {
super.run();
task.doLongTimeTask();
}
} public class Main {
public static void main(String[] args) throws InterruptedException {
Task task = new Task();
ThreadA t1 = new ThreadA(task);
t1.start();
ThreadB t2 = new ThreadB(task);
t2.start();
}
}

测试结果:当一个线程访问object的同步代码块时,另一个线程可以访问该object的非同步代码块。

begin task
begin task
返回值1 thread name=Thread-0
返回值2 thread name=Thread-1
返回值1 thread name=Thread-1
返回值2 thread name=Thread-1
end task
end task

另外synchronized(this)是锁定当前对象的,故和synchronized方法有相同的作用

1. synchronized同步方法

  1)对其他synchronized同步方法或者synchronized(this)同步代码块调用呈现阻塞状态

  2)同一时间内只有一个线程可以执行synchronized同步方法中的代码

2.synchronized(this)同步代码块

  1)对其他synchronized同步方法或者synchronized(this)同步代码块调用呈现阻塞状态

  2)同一时间内只有一个线程可以执行synchronized(this)同步方法中的代码

将任意对象作为对象监视器

public class Service {
public void test(LockObject object){
synchronized (object) {
try {
System.out.println("getLock time="+System.currentTimeMillis()+"thread name="+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println("releaseLock time="+System.currentTimeMillis()+"thread name="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public class ThreadA extends Thread {
private Service service;
private LockObject object;
public ThreadA(Service service,LockObject object) {
this.service = service;
this.object = object;
}
@Override
public void run() {
super.run();
service.test(object);
}
} public class ThreadB extends Thread {
private Service service;
private LockObject object;
public ThreadB(Service service,LockObject object) {
this.service = service;
this.object = object;
}
@Override
public void run() {
super.run();
service.test(object);
}
} public class Main {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
LockObject object = new LockObject();
ThreadA t1 = new ThreadA(service,object);
t1.start();
ThreadB t2 = new ThreadB(service,object);
t2.start();
}
}

测试结果:同步调用,原因是使用了同一个对象监视器

getLock time=1516085547986thread name=Thread-0
releaseLock time=1516085550987thread name=Thread-0
getLock time=1516085550987thread name=Thread-1
releaseLock time=1516085553987thread name=Thread-1

如果不使用同一个对象监视器,则会出现异步的情况

public class Main {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
LockObject object1 = new LockObject();
LockObject object2 = new LockObject();
ThreadA t1 = new ThreadA(service,object1);
t1.start();
ThreadB t2 = new ThreadB(service,object2);
t2.start();
}
}
getLock time=1516085648021thread name=Thread-0
getLock time=1516085648021thread name=Thread-1
releaseLock time=1516085651021thread name=Thread-0
releaseLock time=1516085651022thread name=Thread-1

最后要理解synchronized,其实最主要的是理解synchronized方法和synchronized代码块使用的是什么对象监视器,它们是通过锁定对象监视器来实现同步功能的

1. synchronized同步实例方法和synchronized(this)的对象监视器是对象,它将持有对象锁

2. synchronized同步静态实例方法和synchronized(class)的对象监视器是class文件,它将持有Class锁

java多线程编程之synchronized的更多相关文章

  1. Java并发编程之synchronized

    在Java编程中,为了保证线程安全,有3种不同的思路1.互斥同步:包括synchronized和lock等. 2.非阻塞同步:如AtomicInteger的increaseAndGet()方法等. 3 ...

  2. Java并发编程之synchronized关键字

    整理一下synchronized关键字相关的知识点. 在多线程并发编程中synchronized扮演着相当重要的角色,synchronized关键字是用来控制线程同步的,可以保证在同一个时刻,只有一个 ...

  3. Java 多线程编程之:notify 和 wait 用法

    wait 和 notify 简介 wait 和 notify 均为 Object 的方法: Object.wait() —— 暂停一个线程 Object.notify() —— 唤醒一个线程 从以上的 ...

  4. Java 多线程编程之九:使用 Executors 和 ThreadPoolExecutor 实现的 Java 线程池的例子

    线程池用来管理工作线程的数量,它持有一个等待被执行的线程的队列.         java.util.concurrent.Executors 提供了 java.util.concurrent.Exe ...

  5. Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...

  6. Java高性能编程之CAS与ABA及解决方法

    Java高性能编程之CAS与ABA及解决方法 前言 如果喜欢暗色调的界面或者想换换界面,可以看看我在个人博客发布的 Java高性能编程之CAS与ABA及解决方法. CAS概念 CAS,全称Compar ...

  7. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  8. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

  9. [转] iOS多线程编程之NSOperation和NSOperationQueue的使用

    <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...

随机推荐

  1. php第十九节课

    JQUERY <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  2. 玩转vim编辑器

    1.vim 编辑器可以自定义配置:包含初始化命令的文件叫vimrc(h vimrc),version ---查看版本号.系统-用户配置文件所在位置. 2. 可视模式: 操作一块区域代码: 按v    ...

  3. 48.cartinality的基本用法

    主要知识点 cartinality的用法     es去重用的是cartinality metric算法,对每个bucket中的指定的field进行去重,然后获取去重后的count,类似于count( ...

  4. Ubuntu_linux系统与网络服务管理

    1.远程telnet联机:telnetd: 2.远程加密ssh联机:openssh: 3.webmin远程联机:webmin: 3.VNC远程图像界面控制:vino: 4.NAT网关服务器:iptab ...

  5. 初识Scrapy——1—scrapy简单学习,伯乐在线实战、json数据保存

    Scrapy——1 目录 什么是Scrapy框架? Scrapy的安装 Scrapy的运行流程 Scrapy的使用 实战:伯乐在线案例(json文件保存) 什么是Scrapy框架? Scrapy是用纯 ...

  6. GeoTrust 企业(OV)型 增强版(EV) SSL证书

      GeoTrust 企业(OV)型 增强版(EV) SSL证书(GeoTrust True BusinessID with EV SSL Certificates),验证域名所有权,更严格的验证企业 ...

  7. [bzoj2783][JLOI2012]树_树的遍历

    树 bzoj2783 JLOI2012 题目大意:给定一棵n个点的树.求满足条件的路径条数.说一个路径是满足条件的,当且仅当这条路径上每个节点深度依次递增且点权和为S. 注释:$1\le n\le 1 ...

  8. 洛谷 P2997 [USACO10NOV]旗帜Banner

    P2997 [USACO10NOV]旗帜Banner 题目背景 题目大意(by:曹彦臣): 平面上有(0,0)到(n,m)的(n+1)*(m+1)个点.问有多少点对所连的线段不过其他点,且长度在[l, ...

  9. Bitnami LNMP集成包安装简单总结

    前言发送图文消息时间点,访问量大,请求并发多,业务web机处理不过来,新增加了2台web机应对.搞过Linux软件安装的都知道,各种库的依赖会把人搞崩溃,尤其是服务器不能访问外网的情况下,会非常的蛋疼 ...

  10. Unity图片变灰的方式

    http://www.tuicool.com/articles/Vruuqme NGUI中的Button差点儿是最经常使用到的控件之中的一个,而且能够组合各种组件(比方UIButtonColor,UI ...