synchronized关键字小结(一)
1. synchronized同步方法
1) synchronized修饰方法,表示方法是同步的,当某线程进入并拿到当前整个对象的锁时
a. 其他synchronized方法排队等锁
b. 非synchronized方法可异步执行
示例代码(折叠)
package com.khlin.thread;
public class SynchronizedTest {
public static void main(String[] args) {
Service service = new Service();
/**
* A B 两个方法是同步的,因此访问A时候,要等A方法执行完,A线程释放锁,B线程才能拿到锁从而访问B方法。
* 而C方法并不是同步的,可以异步执行
*/
ThreadA threadA = new ThreadA(service);
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.start();
ThreadC threadC = new ThreadC(service);
threadC.start();
}
}
class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
public void run() {
super.run();
service.printA();
}
}
class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
public void run() {
super.run();
service.printB();
}
}
class ThreadC extends Thread {
private Service service;
public ThreadC(Service service) {
this.service = service;
}
public void run() {
super.run();
service.printC();
}
}
class Service {
public synchronized void printA() {
System.out.println("enter printA. thread name: "
+ Thread.currentThread().getName());
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("leaving printA. thread name: "
+ Thread.currentThread().getName());
}
public synchronized void printB() {
System.out.println("enter printB. thread name: "
+ Thread.currentThread().getName());
System.out.println("leaving printB. thread name: "
+ Thread.currentThread().getName());
}
public void printC() {
System.out.println("enter printC. thread name: "
+ Thread.currentThread().getName());
System.out.println("leaving printC. thread name: "
+ Thread.currentThread().getName());
}
}
synchronized方法
运行结果:

2) 拥有锁重入的功能,当一个线程获得一个对象锁之后 ,再次请求此对象锁的时候是可以再次获得的。
示例代码,修改上面示例代码,在A方法后面调用B方法,可以再次获得锁,运行结果:

3) 重写方法后,synchronized关键字并不继承。但没有被重写的方法,仍然是同步的。
package com.khlin.thread;
public class SynchronizedTest {
public static void main(String[] args) {
/**
* 子类方法的实现若调用了父类的同步方法,一样有效
*/
SubService service = new SubService();
/**
* A B 两个方法是同步的,因此访问A时候,要等A方法执行完,A线程释放锁,B线程才能拿到锁从而访问B方法。
* 而C方法并不是同步的,可以异步执行
*/
ThreadA threadA = new ThreadA(service);
threadA.setName("threadA");
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.setName("threadB");
threadB.start();
ThreadC threadC = new ThreadC(service);
threadC.setName("threadC");
threadC.start();
}
}
class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
public void run() {
super.run();
service.printA();
// service.printB();
}
}
class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
public void run() {
super.run();
service.printB();
}
}
class ThreadC extends Thread {
private Service service;
public ThreadC(Service service) {
this.service = service;
}
public void run() {
super.run();
service.printC();
}
}
class Service {
public synchronized void printA() {
System.out.println("enter printA. thread name: "
+ Thread.currentThread().getName());
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("leaving printA. thread name: "
+ Thread.currentThread().getName());
// printB();
}
public synchronized void printB() {
System.out.println("enter printB. thread name: "
+ Thread.currentThread().getName());
System.out.println("leaving printB. thread name: "
+ Thread.currentThread().getName());
}
public void printC() {
System.out.println("enter printC. thread name: "
+ Thread.currentThread().getName());
System.out.println("leaving printC. thread name: "
+ Thread.currentThread().getName());
}
}
class SubService extends Service {
public void printSubA() {
System.out.println("enter printSubA. thread name: "
+ Thread.currentThread().getName());
printA();
System.out.println("leaving printSubA. thread name: "
+ Thread.currentThread().getName());
}
}
运行结果和1)是一样的。
2. synchronized同步代码块
同步代码块,通过synchronized(一个对象)的写法,把一个代码块变成同步的。
其中,括号里待同步的对象,也可以使用this关键字,指向当前对象,这时与synchronized方法效果是一样的。
1) 被同步的对象是this的情况
与synchronized方法效果一样,示例代码:
package com.khlin.thread;
public class SynchronizedTestSecond {
public static void main(String[] args) {
ServiceSecond service = new ServiceSecond();
ThreadAA threadAA = new ThreadAA(service);
threadAA.setName("ThreadAA");
threadAA.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ThreadBB threadBB = new ThreadBB(service);
threadBB.setName("ThreadBB");
threadBB.start();
}
}
class ServiceSecond {
public void methodA() {
String threadName = Thread.currentThread().getName();
synchronized (this) {
System.out.println("invoke methodA. " + threadName);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("finish invoking methodA. " + threadName);
}
}
public synchronized void methodB() {
String threadName = Thread.currentThread().getName();
System.out.println("invoke methodB. " + threadName);
System.out.println("finish invoking methodA. " + threadName);
}
}
class ThreadAA extends Thread {
ServiceSecond service = new ServiceSecond();
public ThreadAA(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodA();
}
}
class ThreadBB extends Thread {
ServiceSecond service = new ServiceSecond();
public ThreadBB(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodB();
}
}
运行结果:

2) 被同步的对象非this的情况
假设synchronized(x),此时,访问x对象里的同步方法,是同步访问的。
而访问主对象的同步方法,不受同步影响,属于异步。
让我们把上面的代码改为,synchronized(operation),锁住另一个对象。
package com.khlin.thread;
public class SynchronizedTestSecond {
public static void main(String[] args) {
ServiceSecond service = new ServiceSecond();
/**
* 锁住了operation对象,该对象的同步方法必须等待锁
* 而methodB并不属于该对象,ServiceSecond对象的锁,其实线程AA并没有获取,所以线程BB可以异步访问methodB方法。
*/
ThreadAA threadAA = new ThreadAA(service);
threadAA.setName("ThreadAA");
threadAA.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ThreadBB threadBB = new ThreadBB(service);
threadBB.setName("ThreadBB");
threadBB.start();
}
}
class ServiceSecond {
private ServiceOperation operation = new ServiceOperation();
public void methodA() {
String threadName = Thread.currentThread().getName();
synchronized (operation) {
System.out.println("invoke methodA. " + threadName);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("finish invoking methodA. " + threadName);
}
}
public synchronized void methodB() {
String threadName = Thread.currentThread().getName();
System.out.println("invoke methodB. " + threadName);
System.out.println("finish invoking methodB. " + threadName);
}
}
class ServiceOperation {
public synchronized void methodOperation() {
System.out.println("this is operation method.");
}
}
class ThreadAA extends Thread {
ServiceSecond service = new ServiceSecond();
public ThreadAA(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodA();
}
}
class ThreadBB extends Thread {
ServiceSecond service = new ServiceSecond();
public ThreadBB(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodB();
}
}
运行结果:

因为线程BB在访问methodB的时候,service对象的锁并没有被占用着,所以可以直接占用并调用方法。
3. 静态方法的synchronized方法和synchronized(class)方法
这是对类加锁,注意,在java中,类是一种特殊的对象。
原理与上述的非静态方法同步是一样的,不再赘述。
示例代码:
package com.khlin.thread;
public class SynchronizedStatic {
public static void main(String[] args) {
ThreadAAA threadAAA = new ThreadAAA();
threadAAA.setName("ThreadAAA");
threadAAA.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ThreadBBB threadBBB = new ThreadBBB();
threadBBB.setName("ThreadBBB");
threadBBB.start();
}
}
class StaticService {
public synchronized static void methodA()
{
String threadname = Thread.currentThread().getName();
System.out.println("invoking methodA. " + threadname);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("finish methodA. " + threadname);
}
public synchronized static void methodB()
{
String threadname = Thread.currentThread().getName();
System.out.println("invoking methodB. " + threadname);
System.out.println("finish methodB. " + threadname);
}
}
class ThreadAAA extends Thread {
public void run() {
StaticService.methodA();
}
}
class ThreadBBB extends Thread {
public void run() {
StaticService.methodB();
}
}
运行结果:

synchronized关键字小结(一)的更多相关文章
- 深入理解java中的synchronized关键字
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D ...
- Java的synchronized关键字:同步机制总结
JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块.搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程 ...
- synchronized关键字以及实例锁 类锁
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this ...
- synchronized关键字简介 多线程中篇(十一)
前面说过,Java对象都有与之关联的一个内部锁和监视器 内部锁是一种排它锁,能够保障原子性.可见性.有序性 从Java语言层面上说,内部锁使用synchronized关键字实现 synchronize ...
- java synchronized关键字浅析
synchronized这个关键字想必学Java的人都应该知道. 直接上例子: 方法级别实例 public class AtomicInteger { private int index; publi ...
- Java:synchronized关键字引出的多种锁
前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这 ...
- 线程中synchronized关键字和lock接口的异同
一.synchronized关键字 1.可以用来修饰代码块 synchronized (this) { // 同步的关键字 this 表示当前线程对象 if (num == 0) { break; } ...
- 从JAVA看C#中volatile和synchronized关键字的作用
最近一直在想C#中 volatile关键字到底是用来干什么的?查了很多.NET的文章都是说用volatile修饰的变量可以让多线程同时修改,这是什么鬼... 然后查到了下面这篇JAVA中关于volat ...
- Java多线程系列--“基础篇”04之 synchronized关键字
概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...
随机推荐
- PHP 'ext/gd/gd.c' gdImageCrop整数符号错误漏洞
漏洞版本: PHP 5.5.x 漏洞描述: CVE ID:CVE-2013-7328 PHP是一种HTML内嵌式的语言. PHP 'ext/gd/gd.c' gdImageCrop函数存在多个整数符号 ...
- 使用console进行性能测试和计算代码运行时间
对于前端开发人员,在开发过程中经常需要监控某些表达式或变量的值,如果使用用debugger会显得过于笨重,最常用的方法是会将值输出到控制台上方便调试.最常用的语句就是console.log(expre ...
- Android的string-array数据源简单使用
在Android中,用string-array是一种简单的提取XML资源文件数据的方法. 例子如下: 把相应的数据放到values文件夹的arrays.xml文件里 <?xml version= ...
- clone Control event handlers at run time
var btn2 =newButton(); btn2.Text= btn1.Text; btn2.size = btn1.size; To clone all events of any WinFo ...
- Tomcat启动时为什么要配置CATALINA_HOME环境变量??
CATALINA_HOME的值被设为Tomcat的安装目录,如果环境变量CATALINA_HOME已经存在,则通过这个环境变量调用bin目录下的“catalina.bat start”命令 1.Tom ...
- javaweb css教程
CSS 1.css的简介 * css: 层叠样式表 ** 层叠:一层一层的 ** 样式表: 很多的属性和属性值 * 是页面显示效果更加好 * CSS将网页内容和显示样式进行分离,提高了显示功能. 2. ...
- HDU 4135 Co-prime
思路:直接用求(b,1)范围内互质的数,(a-1,1)范围内互质的数.再求反 就是敲一下容斥模板 #include<cstdio> #include<cstring> #inc ...
- 使用 Windows PowerShell 管理Windows Azure映像
你可以使用 Azure PowerShell 模块中的 cmdlet 管理可供你的 Azure 订阅使用的映像.这包括 Azure 提供的映像以及你上载的映像.对于某些映像任务,你还可以使用 Azur ...
- Linux经久不衰的应用程序
Linux里面的应用程序一贯以高安全性,高性价比(功能/所占空间),此次记录一下Linux里面比较常用的而且经久不衰的应用程序. Shell: bash(它结合了 csh ...
- 定时备份为Sharepoint做网站备份,并删除指定日期的备份
一.创建bat文件 @echo cd \ c: cd "Program Files\Common Files\Microsoft Shared\web server extensions\1 ...