synchronized的作用
一、同步方法
public synchronized void methodAAA(){ //…. }
锁定的是调用这个同步方法的对象
测试:
a、不使用这个关键字修饰方法,两个线程调用同一个对象的这个方法。
目标类:
public class TestThread { public void execute(){ //synchronized,未修饰 for(int i=0;i<100;i++){ System.out.println(i); } } }
线程类:
public class ThreadA implements Runnable{ TestThread test=null; public ThreadA(TestThread pTest){ //对象有外部引入,这样保证是同一个对象 test=pTest; } public void run() { test.execute(); } }
调用:
TestThread test=new TestThread(); Runnable runabble=new ThreadA(test); Thread a=new Thread(runabble,"A"); a.start(); Thread b=new Thread(runabble,"B"); b.start();
结果:
输出的数字交错在一起。说明不是同步的,两个方法在不同的线程中是异步调用的。
b、修改目标类,增加synchronized修饰
public class TestThread { public synchronized void execute(){ //synchronized修饰 for(int i=0;i<100;i++){ System.out.println(i); } } }
结果:
输出的数字是有序的,首先输出A的数字,然后是B,说明是同步的,虽然是不同的线程,但两个方法是同步调用的。
注意:上面虽然是两个不同的线程,但是是同一个实例对象。下面使用不同的实例对象进行测试。
c、每个线程都有独立的TestThread对象。
目标类:
public class TestThread { public synchronized void execute(){ //synchronized修饰 for(int i=0;i<100;i++){ System.out.println(i); } } }
线程类:
public class ThreadA implements Runnable{ public void run() { TestThread test=new TestThread(); test.execute(); } }
调用:
Runnable runabble=new ThreadA(); Thread a=new Thread(runabble,"A"); a.start(); Thread b=new Thread(runabble,"B"); b.start();
结果:
输出的数字交错在一起。说明虽然增加了synchronized 关键字来修饰方法,但是不同的线程调用各自的对象实例,两个方法仍然是异步的。
引申:
对于这种多个实例,要想实现同步即输出的数字是有序并且按线程先后顺序输出,我们可以增加一个静态变量,对它进行加锁(后面将说明锁定的对象)。
修改目标类:
public class TestThread { private static Object lock=new Object(); //必须是静态的。 public void execute(){ synchronized(lock){ for(int i=0;i<100;i++){ System.out.println(i); } } } }
二、同步代码块
public void method(SomeObject so){ synchronized(so) //….. } }
锁定一个对象,其实锁定的是该对象的引用(object reference)
谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以按上面的代码写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它必须是一个对象)来充当锁(上面的解决方法就是增加了一个状态锁)。
a、锁定一个对象,它不是静态的
private byte[] lock = new byte[0]; // 特殊的instance变量
目标类:
public class TestThread { private Object lock=new Object(); public void execute(){ synchronized(lock){ //增加了个锁,锁定了对象lock,在同一个类实例中,是线程安全的,但不同的实例还是不安全的。因为不同的实例有不同对象锁lock. for(int i=0;i<100;i++){ System.out.println(i); } } } }
其实上面锁定一个方法,等同于下面的:
public void execute(){ synchronized(this){ //同步的是当然对象 for(int i=0;i<100;i++){ System.out.println(i); } } }
b、锁定一个对象或方法,它是静态的
这样锁定,它锁定的是对象所属的类
public synchronized static void execute(){ //... } 等同于
public class TestThread { public static void execute(){ synchronized(TestThread.class){ // } } }
测试:
目标类:
public class TestThread { private static Object lock=new Object(); public synchronized static void execute(){ //同步静态方法 for(int i=0;i<100;i++){ System.out.println(i); } } public static void execute1(){ for(int i=0;i<100;i++){ System.out.println(i); } } public void test(){ execute(); //输出是有序的,说明是同步的 //execute1(); //输出是无须的,说明是异步的 } } 线程类:调用不同的方法,于是建立了两个线程类 public class ThreadA implements Runnable{ public void run() { TestThread.execute();//调用同步静态方法 } } public class ThreadB implements Runnable{ public void run() { TestThread test=new TestThread(); test.test();//调用非同步非静态方法 } } 调用: Runnable runabbleA=new ThreadA(); Thread a=new Thread(runabbleA,"A"); a.start(); Runnable runabbleB=new ThreadB(); Thread b=new Thread(runabbleB,"B"); b.start(); 注意: 用synchronized 来锁定一个对象的时候,如果这个对象在锁定代码段中被修改了,则这个锁也就消失了。看下面的实例: 目标类: public class TestThread { private static final class TestThreadHolder { private static TestThread theSingleton = new TestThread(); public static TestThread getSingleton() { return theSingleton; } private TestThreadHolder() { } } private Vector ve =null; private Object lock=new Object(); private TestThread(){ ve=new Vector(); initialize(); } public static TestThread getInstance(){ return TestThreadHolder.getSingleton(); } private void initialize(){ for(int i=0;i<100;i++){ ve.add(String.valueOf(i)); } } public void reload(){ synchronized(lock){ ve=null; ve=new Vector(); //lock="abc"; for(int i=0;i<100;i++){ ve.add(String.valueOf(i)); } } System.out.println("reload end"); } public boolean checkValid(String str){ synchronized(lock){ System.out.println(ve.size()); return ve.contains(str); } } }
说明:在reload和checkValid方法中都增加了synchronized关键字,对lock对象进行加锁。在不同线程中对同一个对象实例分别调用reload和checkValid方法。
在reload方法中,不修改lock对象即注释lock="abc"; ,结果在控制台输出reload end后才输出100。说明是同步调用的。
如果在reload方法中修改lock对象即去掉注释,结果首先输出了一个数字(当前ve的大小),然后输出reload end。说明是异步调用的。
2、单例模式中对多线程的考虑
public class TestThread { private static final class TestThreadHolder { private static TestThread theSingleton = new TestThread(); public static TestThread getSingleton() { return theSingleton; } private TestThreadHolder() { } } private Vector ve =null; private Object lock=new Object(); private TestThread(){ ve=new Vector(); initialize(); } public static TestThread getInstance(){ return TestThreadHolder.getSingleton(); } }
说明:增加了一个内部类,在内部类中申明一个静态的对象,实例化该单例类,初始化的数据都在单例类的构造函数中进行。这样保证了多个实例同时访问的时候,初始化的数据都已经成功初始化了。
总结:
A. 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁,所以首先应知道需要加锁的对象
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
synchronized的作用的更多相关文章
- JAVA关键词synchronized的作用
记下来,很重要. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchron ...
- 搜狗一道java题目 关于对象 synchronized 关键字作用在 int, integer
第一次见到这个题目,我觉得自己没学到java,太浅了,其实这个问题没有考synchronized关键字,只是考什么是对象? 1.在java编程思想的第二章有一句话; 一切都是对象,很可惜int,c ...
- Android 虹软2.0人脸识别,注册失败问题 分析synchronized的作用
人脸识别需要init初始化(FaceServer中),离开时需要unInit销毁:当一个含有人脸识别的界面A跳向另一个含有人脸识别的界面B时,由于初始化和销毁都是对FaceServer类加锁(sync ...
- synchronized 的作用?
在 Java 中,synchronized 关键字是用来控制线程同步的,就是在多线程的环境 下,控制 synchronized 代码段不被多个线程同时执行. synchronized 既可以加在一段代 ...
- 从JAVA看C#中volatile和synchronized关键字的作用
最近一直在想C#中 volatile关键字到底是用来干什么的?查了很多.NET的文章都是说用volatile修饰的变量可以让多线程同时修改,这是什么鬼... 然后查到了下面这篇JAVA中关于volat ...
- Java 关键字volatile 与 synchronized 作用与区别
1,volatile 它所修饰的变量不保留拷贝,直接访问主内存中的. 在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器).为了性能,一个线程会在自己 ...
- synchronized和lock的作用与对比
一.synchronized的作用 synchronized是java中的一个关键字,用于线程同步.1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象 ...
- java中关键字volatile的作用
用在多线程,同步变量. 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况.volatile就是用来 ...
- Thread 学习记录 <1> -- volatile和synchronized
恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1; ...
随机推荐
- 关于vue生命周期中的同步异步的理解
在vue官网中介绍生命周期的图如下: 主要测试代码如下: 主要是测试前四个生命周期beforeCreate,created,beforeMount,mounted,里面同步和异步的执行顺序,其它的类似 ...
- ubuntu16.04 英文环境安装google chrome
1.下载google wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 2.安装缺少的依赖 ...
- Java之File类
一.初见File类 java.io.File类代表系统中的文件(文件或目录) 常用构造方法 File(String pathname) File(String parent, String child ...
- C++进阶引导
1.C++的用途和意义 t0185b047e29feffc26.jpg 总体来说,C++作为一门软件开发语言,它的流行度是在减少的.主要原因在于语言的复杂和灵活导致软件开发成本提高,这体现在开发周期和 ...
- js变量提升和函数提升
变量,作为编程语言最基础的部分,每种语言的变量不尽相同,但又大径相庭.大部分编程语言的变量有块级作用域,如if.for.while... 但JavaScript不纯在块级作用域,而是函数作用域,并且有 ...
- 微信授权登录(PHP)
微信授权登录(PHP) 微信授权 OAuth2.0授权 微信网页授权 主要是在项目中遇到网页授权登录这个需求,就对此做些总结记录. OAuth2.0授权 OAuth是一个开放协议,允许用户让第三方应用 ...
- vijos1325 桐桐的糖果计划
Description 桐桐是一个快乐的小朋友,他生活中有许多许多好玩的事,让我们一起来看看吧-- 桐桐很喜欢吃棒棒糖.他家处在一大堆糖果店的附近. 但是,他们家的区域经常出现塞车.塞人等情况,这导致 ...
- thinkphp中find()和select()的区别
1.find()是查找符合条件的第一条数据,返回的是一个一维数组: select()是查找符合条件的所有的数据,返回的是一个二维数组: 2.以下案例 $tech=M('techlevel','HR_C ...
- R语言统计分析技术研究 特征值选择技术要点
特征值选择技术要点 作者:王立敏 文章来源: 网络 1.特征值 特征值是线性代数中的一个重要概念.在数学,物理学,化学,计算机等领域有着广泛的应用. ...
- Spring boot 1: 使用IDEA创建Spring boot项目
项目用到的环境: Windows 10 JDK8 IntelliJ IDEA 2017.1.3 Apache Tomcat 8 Maven 3.3.3 使用IDEA新建spring boot项目 新建 ...