[java] java synchronized 关键字详解
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。
一、synchronized同步方法
1.synchronized 同步方法,为对象锁
public class ExceptionReleaseLock {
public synchronized void testLockException(){
if (Thread.currentThread().getName().equals("A")){
System.out.println("线程名字为:"+Thread.currentThread().getName()+" 开始运行时间:"+System.currentTimeMillis());
for(int i=0;i<200;i++){
while(i>20){
System.out.println("i="+i);
Integer.parseInt("abcd");
}
}
}else{
System.out.println("B线程运行时间:"+System.currentTimeMillis());
}
}
}
2.synchronized 锁重入
当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞.
我们来看看synchronized,它拥有强制原子性的内置锁机制,是一个重入锁,所以在使用synchronized时,当一个线程请求得到一个对象锁后再次请求此对象锁,可以再次得到该对象锁,就是说在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以拿到锁。否则,就会造成死锁。
/**
* Created by Administrator on 2015/12/30 0030.
*
* 锁重入机制
*/
public class LockSyn { public synchronized void a(){
System.out.println("a()");
b();
} public synchronized void b(){
System.out.println("b()");
c();
} public synchronized void c(){
System.out.println("c()");
}
}
public class TestLockSyn {
public static void main(String[] args){
new LockSyn().a();
}
}
输出结果:
a()
b()
c()
当存在继承关系时,子类可以通过可重入锁调用父类的同步方法。
public class Animal {
synchronized public void eat(){
System.out.println("Animal eat foods");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Cat extends Animal {
synchronized public void eatFish(){
System.out.println("cat eatFish...");
try {
Thread.sleep(2000);
this.eat();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试:
public class TestAnimal {
public static void main(String[] args){
Cat cat = new Cat();
cat.eatFish();
}
}
输出:
cat eatFish...
Animal eat foods
我们再来看看重入锁是怎么实现可重入性的,其实现方法是为每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。
3. 发生异常,锁自动释放
public class ExceptionReleaseLock {
public synchronized void testLockException(){
if (Thread.currentThread().getName().equals("A")){
System.out.println("线程名字为:"+Thread.currentThread().getName()+" 开始运行时间:"+System.currentTimeMillis());
for(int i=0;i<200;i++){
while(i>20){
System.out.println("i="+i);
Integer.parseInt("abcd");
}
}
}else{
System.out.println("B线程运行时间:"+System.currentTimeMillis());
}
}
}
public class ExceptionReleaseThread1 extends Thread {
private ExceptionReleaseLock exceptionReleaseLock;
public ExceptionReleaseThread1(ExceptionReleaseLock lock){
this.exceptionReleaseLock=lock;
}
@Override
public void run() {
exceptionReleaseLock.testLockException();
}
}
public class ExceptionReleaseThread2 extends Thread {
private ExceptionReleaseLock exceptionReleaseLock;
public ExceptionReleaseThread2(ExceptionReleaseLock lock){
this.exceptionReleaseLock=lock;
}
@Override
public void run() {
exceptionReleaseLock.testLockException();
}
}
测试:
/**
* Created by Administrator on 2015/12/30 0030.
*
* 发生异常后,锁自动释放
*/
public class TestExceptionRelease { public static void main(String[] args){
ExceptionReleaseLock lock = new ExceptionReleaseLock();
ExceptionReleaseThread1 a = new ExceptionReleaseThread1(lock);
ExceptionReleaseThread2 b = new ExceptionReleaseThread2(lock); a.setName("A");
b.setName("B");
a.start();
b.start();
}
}
输出结果:

A线程发生异常后释放了锁,线程B正常执行。
4. 同步不具有继承性.
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("noSynchronized ....");
}
}
需要在方法前加上synchronized同步。
二、synchronized 同步语句块
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为
synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可
以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供
了更好的解决办法,那就是 synchronized 块。
2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机
制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
对synchronized(this)的一些理解
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线
程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized
(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)
同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个
object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用
package com.xwolf.java.thread.ch2; /**
* Created by Administrator on 2016/1/4 0004.
*
* synchronized 代码块 同样是对象加锁
*/
public class SyncBlock { public synchronized void a(){
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" begin&&&&&&&&&&&&&&&");
try {
Thread.sleep(2000);
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" end$$$$$$$$$$$$$$$$$$$$$$"); } catch (InterruptedException e) {
e.printStackTrace();
}
} public void b(){
try { synchronized (this){
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" begin&&&&&&&&&&&&&&&");
Thread.sleep(2000);
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" end$$$$$$$$$$$$$$$$$$$$$$");
} } catch (InterruptedException e) {
e.printStackTrace();
}
} }
public class SyncThreadA extends Thread {
private SyncBlock block;
SyncThreadA(SyncBlock block){
this.block=block;
}
@Override
public void run() {
block.a();
}
}
public class SyncThreadB extends Thread {
private SyncBlock block;
SyncThreadB(SyncBlock block){
this.block=block;
}
@Override
public void run() {
block.b();
}
}
public class SyncThreadTest {
public static void main(String[] args){
SyncBlock block =new SyncBlock();
SyncThreadA a = new SyncThreadA(block);
a.setName("A");
SyncThreadB b = new SyncThreadB(block);
b.setName("B");
a.start();
b.start();
}
}

三、static synchronized 和非static synchronized 方法
package com.xwolf.java.thread.ch2; /**
* Created by Administrator on 2016/1/4 0004.
*
* 验证static方法和非static方法synchronized 区别
*/
public class StaticSync { public synchronized static void a(){
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" begin&&&&&&&&&&&&&&&"); try {
Thread.sleep(2000);
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" end$$$$$$$$$$$$$$$$$$$$$$"); } catch (InterruptedException e) {
e.printStackTrace();
} } public synchronized static void b(){
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" begin&&&&&&&&&&&&&&&"); try {
Thread.sleep(2000);
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" end$$$$$$$$$$$$$$$$$$$$$$"); } catch (InterruptedException e) {
e.printStackTrace();
} } public synchronized void c(){
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" begin&&&&&&&&&&&&&&&"); try {
Thread.sleep(2000);
System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" end$$$$$$$$$$$$$$$$$$$$$$"); } catch (InterruptedException e) {
e.printStackTrace();
} }
}
package com.xwolf.java.thread.ch2; /**
* Created by Administrator on 2016/1/4 0004.
*/
public class StaticThreadA extends Thread{ private StaticSync staticSync; public StaticThreadA(StaticSync sync){
this.staticSync=sync;
} @Override
public void run() {
staticSync.a();
}
}
测试:
package com.xwolf.java.thread.ch2; /**
* Created by Administrator on 2016/1/4 0004.
*/
public class StaticSyncTest { public static void main(String[] args){ StaticSync sync = new StaticSync(); StaticThreadA a = new StaticThreadA(sync);
a.setName("A"); StaticThreadB b = new StaticThreadB(sync); b.setName("B"); StaticThreadC c = new StaticThreadC(sync);
c.setName("C"); a.start();
b.start();
c.start();
} }

当一个synchronized关键字修饰的方法同时又被static修饰,之前说过,非静态的同步方法会将对象上锁,但是静态方法不属于对象,而是属于类,它会将这个方法所在的类的Class对象上锁。一个类不管生成多少个对象,它们所对应的是同一个Class对象。
[java] java synchronized 关键字详解的更多相关文章
- Java多线程(三)—— synchronized关键字详解
一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...
- “全栈2019”Java多线程第十六章:同步synchronized关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java synchronized 关键字详解
Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...
- java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系
本文关键词: java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系 跳出循环 带标签的continue和break 嵌套循环 深入continue ...
- Java 多线程(六) synchronized关键字详解
多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchroniz ...
- Java中Volatile关键字详解
一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...
- Java中Volatile关键字详解(转载)
转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...
- Java中Volatile关键字详解 (转自郑州的文武)
java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...
- 从线程池到synchronized关键字详解
线程池 BlockingQueue synchronized volatile 前段时间看了一篇关于"一名3年工作经验的程序员应该具备的技能"文章,倍受打击.很多熟悉而又陌生的知识 ...
随机推荐
- 常用的Eclipse设置
每次新建work space的时候,我都要修改一些默认设置,每次都要花一些时间找在哪里设置,总结如下. 启动加速 1. 去掉XML Validataion Windows --> Prefere ...
- python格式化
1.百分号格式如下: %[(name)] [flags] [.precision] typecode (name):可选,获取指定key的值flags:可选,:width,占有宽度.precision ...
- ny168 房间安排
房间安排 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述 2010年上海世界博览会(Expo2010),是第41届世界博览会.于2010年5月1日至10月31日期间,在中 ...
- java 生成泛型的参数的实例 T t=new T()
方法1 ParameterizedType ptype = (ParameterizedType) this.getClass().getGenericSuperclass(); Class claz ...
- JAVA-JSP运行机制
相关资料: <21天学通Java Web开发> 实例操作: 1.调用结束之前的实例“HelloWorld.JSP”页面.2.打开“D:\Ruanjian\apache-tomcat-8.5 ...
- javascript mediator pattern
定义 定义一个对象,它封装一组相互作用的对象.中介者促使对象之间保持通讯但是又松耦合,你可以很独立的改变他们的相互作用. 提要 中介者提供一个权威中心,用来控制一组对象之间的相互作用.这种模式在这种情 ...
- vim 移植记录
下载两个源码包: vim : ftp://ftp.vim.org/pub/vim/unix/vim-7.4.tar.bz2\ ncurses-5.8.tar.gz http://ftp.gnu.org ...
- hdu6199 gems gems gems dp+博弈
/** 2017 ACM/ICPC Asia Regional Shenyang Online 解题报告 题目:hdu6199 gems gems gems 链接:http://acm.hdu.edu ...
- 使用DroneKit控制无人机
DroneKit-Python是一个用于控制无人机的Python库.DroneKit提供了用于控制无人机的API,其代码独立于飞控,单独运行在机载电脑(Companion Computer)或其他设备 ...
- JVM中的垃圾回收
GC 垃圾回收回收什么 Java的内存分配原理与C/C++不同.C/C++每次申请内存时都要malloc进行系统调用.而系统调用发生在内核空间,每次都要中断进行切换,这须要一定的开销. 而Java虚拟 ...