synchronized用法详解
1、介绍
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块。
2、修饰对象
2.1、修饰this,当前对象,这里的this指的是执行这段代码的对象,synchronized得到的锁就是this这个对象的锁。
线程thread1 访问对象testSy1的带有同步代码块的add()时,其他线程可以访问该对象的add()方法吗?
public class TestSy1 implements Runnable{
private int number;
TestSy1(){
number = 0;
}
public void add(){
synchronized (this){
for(int i=0;i<4;i++){
try{
System.out.println(Thread.currentThread().getName()+":thread:"+(number++));
Thread.sleep(500);
}catch (Exception e){
System.out.println("异常");
}
}
}
System.out.println("add");
}
public void show(){
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + " 非同步:" + number);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("show");
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
add();
}else{
add();
}
}
public static void main(String[] args){
TestSy1 testSy1 = new TestSy1();
Thread thread1 = new Thread(testSy1,"thread1");
Thread thread2 = new Thread(testSy1,"thread2");
thread1.start();
thread2.start();
}
}
结果如下:
thread1:thread:0
thread1:thread:1
thread1:thread:2
thread1:thread:3
thread2:thread:4
thread2:thread:5
thread2:thread:6
thread2:thread:7
可见,其他线程不能访问add()方法。
修改一下run()
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
add();
}else{
show();
}
}
结果如下:
thread1:thread:0
thread2 非同步:1
thread1:thread:1
thread2 非同步:2
thread2 非同步:2
thread1:thread:2
thread1:thread:3
thread2 非同步:4
thread2 非同步:4
其他线程可以访问该对象的show()方法。
那其他线程可以访问,其他对象的同步方法吗?
public class TestSy1 implements Runnable{
private int number;
TestSy1(){
number = 0;
}
public void add(){
synchronized (this){
for(int i=0;i<4;i++){
try{
System.out.println(Thread.currentThread().getName()+":thread:"+(number++));
Thread.sleep(500);
}catch (Exception e){
System.out.println("异常");
}
}
}
System.out.println("add");
}
public void show(){
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + " 非同步:" + number);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("show");
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
add();
}else{
add();
}
}
public static void main(String[] args){
TestSy1 testSy1 = new TestSy1();
TestSy1 testSy2 = new TestSy1();
Thread thread1 = new Thread(testSy1,"thread1");
Thread thread2 = new Thread(testSy2,"thread2");
thread1.start();
thread2.start();
}
}
结果如下:
thread1:thread:0
thread2:thread:0
thread1:thread:1
thread2:thread:1
thread1:thread:2
thread2:thread:2
thread1:thread:3
thread2:thread:3
总结:修饰this和修饰非静态方法一样。线程A访问对象A的带有同步代码块的方法A时,其他线程可以访问该对象的非同步方法和其他对象的所有方法。
3、修饰方法
3.1、修饰非静态方法
public class TestMethod implements Runnable{
private static int number;
TestMethod(){
number = 0;
}
public synchronized void m1(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public void m2(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
m1();
}else{
m1();
}
}
public static void main(String[] args){
TestMethod testMethod = new TestMethod();
Thread thread1 = new Thread(testMethod,"thread1");
Thread thread2 = new Thread(testMethod,"thread2");
thread1.start();
thread2.start();
}
}
上述代码中,synchronized 修饰了非静态方法m1(),然后生成两个线程分别访问对象testMethod的m1()方法,结果如下:
thread1:0
thread1:1
thread1:2
thread2:3
thread2:4
thread2:5
可见,synchronized修饰非静态方法时,线程thread1访问testMethod对象的同步方法m1()时,其他线程不能访问testMethod对象的同步方法m1(),那它可以访问testMethod的非同步方法m2()吗?
对上述代码的run()方法进行修改
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
m1();
}else{
m2();//让thread2访问非同步方法m2()
} }
结果如下:
thread1:0
thread2:1
thread1:2
thread2:3
thread1:4
thread2:5
可见,线程thread2可以访问对象testMethod的非同步方法m2(),那线程thread2又可以访问其他对象的同步和非同步方法吗?
package p02;
public class TestMethod implements Runnable{
private static int number;
TestMethod(){
number = 0;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
m1();
}else{
m1();
}
}
public synchronized void m1(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public void m2(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public static void main(String[] args){
TestMethod testMethod = new TestMethod();
TestMethod testMethod1 = new TestMethod();
Thread thread1 = new Thread(testMethod,"thread1");
Thread thread2 = new Thread(testMethod1,"thread2");
thread1.start();
thread2.start();
}
}
结果如下:
thread1:0
thread2:1
thread1:2
thread2:3
thread2:4
thread1:5
可见,其他线程可以访问对象testMethod1的同步方法。
总结:
修饰非静态方法时,线程A访问对象A的非静态同步方法A时,其他线程可以访问该对象的非同步方法以及其他对象的任何方法
3.2、修饰静态方法
因为静态方法是属于类的,不是对象的,所以就不测试其他对象了,感兴趣的话可以自己试一试。
public class TestMethod implements Runnable{
private static int number;
TestMethod(){
number = 0;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
m1();
}else{
m1();
}
}
public static synchronized void m1(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public void m2(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public static void main(String[] args){
TestMethod testMethod = new TestMethod();
Thread thread1 = new Thread(testMethod,"thread1");
Thread thread2 = new Thread(testMethod,"thread2");
thread1.start();
thread2.start();
}
}
上述代码,m1()是静态同步方法,当两个线程同时访问该方法时会发生什么?
thread1:0
thread1:1
thread1:2
thread2:3
thread2:4
thread2:5
当线程thread1访问静态同步方法m1()时,其他线程不能访问m1(),可以访问m2(),结果如下:
thread1:0
thread2:1
thread1:2
thread2:3
thread1:4
thread2:5
如果m2()是非静态同步方法呢?
public class TestMethod implements Runnable{
private static int number;
TestMethod(){
number = 0;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
m1();
}else{
m2();
}
}
public static synchronized void m1(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public synchronized void m2(){
for(int i=0;i<3;i++){
try {
System.out.println(Thread.currentThread().getName()+":"+(number++));
Thread.sleep(200);
}catch (Exception e){
System.out.println("异常");
}
}
}
public static void main(String[] args){
TestMethod testMethod = new TestMethod();
Thread thread1 = new Thread(testMethod,"thread1");
Thread thread2 = new Thread(testMethod,"thread2");
thread1.start();
thread2.start();
}
}
上述代码中,线程thread1访问静态同步方法m1(),线程thread2 访问非静态同步方法m2(),结果如下:
thread1:0
thread2:1
thread1:2
thread2:3
thread2:4
thread1:5
线程thread1访问静态同步方法m1()时,线程thread2可以访问非静态同步方法m2()
总结:修饰静态方法时,作用于类,同时作用于该类的所有对象。所以,线程A访问静态同步方法时,其他线程可以访问非静态同步方法和非同步方法,不可以访问静态同步方法。
4、修饰类
synchronized不可以直接修饰类,但是可以通过synchronized(类名.class)作用于类。修饰类和修饰静态方法一样,也是作用于该类的所有对象。
例子1
public class TestSy1 implements Runnable{
private int number;
TestSy1(){
number = 0;
}
public void add(){
synchronized (TestSy1.class){
for(int i=0;i<4;i++){
try{
System.out.println(Thread.currentThread().getName()+":thread:"+(number++));
Thread.sleep(500);
}catch (Exception e){
System.out.println("异常");
}
}
}
System.out.println("add");
}
public void show(){
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + " 非同步:" + number);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("show");
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
add();
}else{
add();
}
}
public static void main(String[] args){
TestSy1 testSy1 = new TestSy1();
Thread thread1 = new Thread(testSy1,"thread1");
Thread thread2 = new Thread(testSy1,"thread2");
thread1.start();
thread2.start();
}
}
结果如下:
thread1:thread:0
thread1:thread:1
thread1:thread:2
thread1:thread:3
thread2:thread:4
thread2:thread:5
thread2:thread:6
thread2:thread:7
线程A访问带有synchronized(类名.class)的代码的方法时,其他线程不能方法该方法。
例子2
线程A访问带有synchronized (TestSy1.class)的add()方法,其他线程访问非静态同步方法。
public class TestSy1 implements Runnable{
private int number;
TestSy1(){
number = 0;
}
public void add(){
synchronized (TestSy1.class){
for(int i=0;i<4;i++){
try{
System.out.println(Thread.currentThread().getName()+":thread:"+(number++));
Thread.sleep(500);
}catch (Exception e){
System.out.println("异常");
}
}
}
System.out.println("add");
}
public synchronized void show(){
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + " 非同步:" + number);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("show");
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(name.equalsIgnoreCase("thread1")){
add();
}else{
show();
}
}
public static void main(String[] args){
TestSy1 testSy1 = new TestSy1();
TestSy1 testSy2 = new TestSy1();
Thread thread1 = new Thread(testSy1,"thread1");
Thread thread2 = new Thread(testSy1,"thread2");
thread1.start();
thread2.start();
}
}
结果如下:
thread1:thread:0
thread2 非同步:1
thread1:thread:1
thread2 非同步:2
thread1:thread:2
thread2 非同步:3
thread1:thread:3
thread2 非同步:4
thread2 非同步:4
其他线程可以访问非静态同步方法,非同步方法更不要说了。
总结:
如果一个方法内带有synchronized (类名.class)这样的代码块,这个方法就相当于静态同步方法。
线程A方法该类的静态同步方法时,其他线程不可以访问静态同步方法,但是可以访问非静态同步方法和非同步方法。
synchronized用法详解的更多相关文章
- Java并发编程1--synchronized关键字用法详解
1.synchronized的作用 首先synchronized可以修饰方法或代码块,可以保证同一时刻只有一个线程可以执行这个方法或代码块,从而达到同步的效果,同时可以保证共享变量的内存可见性 2.s ...
- Android GLSurfaceView用法详解(二)
输入如何处理 若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件.下面有个例子: java代码: package eoe.ClearTes ...
- Java多线程(三)—— synchronized关键字详解
一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...
- 2020了你还不会Java8新特性?(五)收集器比较器用法详解及源码剖析
收集器用法详解与多级分组和分区 为什么在collectors类中定义一个静态内部类? static class CollectorImpl<T, A, R> implements Coll ...
- Java synchronized 关键字详解
Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...
- C#中string.format用法详解
C#中string.format用法详解 本文实例总结了C#中string.format用法.分享给大家供大家参考.具体分析如下: String.Format 方法的几种定义: String.Form ...
- @RequestMapping 用法详解之地址映射
@RequestMapping 用法详解之地址映射 引言: 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式提交数据时,发现服务器端接受不到提交的数据(服务器端参数绑定没 ...
- linux管道命令grep命令参数及用法详解---附使用案例|grep
功能说明:查找文件里符合条件的字符串. 语 法:grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>] ...
- mysql中event的用法详解
一.基本概念mysql5.1版本开始引进event概念.event既“时间触发器”,与triggers的事件触发不同,event类似与linux crontab计划任务,用于时间触发.通过单独或调用存 ...
随机推荐
- C# xml读取操作
以下xml: <Project> <ProjectMains> <ProjectMain Action="added"> <Project ...
- 【BZOJ1969】[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
[BZOJ1969][Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由 ...
- 在嵌入式、海思、ARM中进行统一的音频AAC编码的必要性
前言 最近来到深圳,跟许多做硬件的小伙伴聊安防.聊互联网.聊技术,受益颇多,其中聊到一点,大家一直都在想,互联网发展如此迅猛,为啥大部分的摄像机还是采用的传统G.726/G.711的音频编码格式呢,如 ...
- 基于传统IPC基础上的RTMP互联网推流摄像机方案设计
在我之前的一篇博客<EasyRTMP内置进入摄像机中实现网络推流直播摄像机的功能>中,我阐述了一种将RTMP推流内置到摄像机系统内部,实现安防摄像机转互联网直播的RTMP推流摄像机功能,如 ...
- Asynchronous_method_invocation 异步方法调用 让步 yielding
zh.wikipedia.org/wiki/同步 [同步不同事件发生 时间一致] 同步(英语:Synchronization),指在一个系统中所发生的事件(event),之间进行协调,在时间上出现一致 ...
- file标签样式修改
1. 这是默认的file样式,无法修改,在网页中用它感觉非常不合群,大部分修改的办法就是把它隐藏,绝对定位一个文本框和一个按钮 这是修改后的样式,之后修改样式就是分别修改文本框和按钮样式了,就非常简单 ...
- 韩国版微信Kakao推出公链,能否用区块链实现全球扩张?
2018年是属于区块链的一年,国内外巨头们纷纷布局区块链产业,前不久韩国最大的移动社交平台Kakao集团正式启动了旗下的第一个公链Klaytn的测试网. 此次宣布只是一次试探性举措,旨在对外公布Kla ...
- Linux就该这么学--命令集合10(vim编辑器)
1.vim编辑器的命令模式中常用的快捷键: dd 删除(剪切)光标所在整行 5dd 删除(剪切)从光标处开始的5行 yy 复制光标所在整行 5yy 复制从光标处开始的5行 p 将之前删除(dd)或复制 ...
- Java 内存模型及GC原理
一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...
- SNMP服务安装 Centos6.8环境网络安装
概念: snmp是英文“Simple Network Management Protocol”的缩写,意为:简单网络管理协议. snmp是目前最常用的环境管理协议. snmp被设计成与协议无关的. s ...