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. 关于css定位的一些总结

    #pay_pic{ overflow: hidden; width: 200px; margin: 0 auto; } table.dataintable { margin-top: 15px; bo ...

  2. Java并发——阿里架构师是如何巧用线程池的!

    一.创建线程 1.创建普通对象,只是在JVM的堆里分配一块内存而已 2.创建线程,需要调用操作系统内核的API,然后操作系统需要为线程分配一系列资源,成本很高 线程是一个重量级对象,应该避免频繁创建和 ...

  3. typeof和instanceof的区别

    typeof和instanceof的区别: typeof typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型.它返回值是一个字符串,该字符串说明运算数的类型.typeof 一般只能 ...

  4. Linux 下phpstudy的安装使用补充说明

    (1)使用方法 在终端中使用sudo 或者 使用管理员账号运行 phpstudy start 开启 (2)命令列表: phpstudy start | stop | restart        开启 ...

  5. JAVA通用工具类

    1.异常验证框架 框架1:com.google.common.base.Preconditions 框架2:org.apache.commons.lang.Validate 框架3:org.apach ...

  6. pop的运用

    pop():弹出列表最后一个元素 练习题: num_list = [12, 45, 34,13, 100, 24, 56, 74, 109] one_list = [] two_list = [] t ...

  7. js 图表转图片

    最近项目上有个需求,是将一些teechart做的图表转换成图片插入自动生成的PDF里,Teechart绘图和如何生成PDF这些这里就不说了,这个任务比较别扭的一点是,图表自动生成,且整个过程中页面不能 ...

  8. 面试:A

    分析 System.Collections.Generic.List<T> 的 Remove<T> 方法和 Clear 方法的实现细节(不允许使用“移除”“清除”这种概念模糊的 ...

  9. Linux之iptables(三、命令--->单主机)

    iptables命令规则格式: iptables [-t table] SUBCOMMAND chain [-m matchname[per-match-options]] -j targetname ...

  10. Serial Fluent UDF on Windows

    test test Table of Contents 1. Serial UDF on Windows OS 1 Serial UDF on Windows OS Note: Udf has to ...