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 关键字详解的更多相关文章

  1. Java多线程(三)—— synchronized关键字详解

    一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...

  2. “全栈2019”Java多线程第十六章:同步synchronized关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. Java synchronized 关键字详解

    Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...

  4. java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系

    本文关键词: java continue break 关键字 详解 区别  用法 标记  标签 使用 示例 联系   跳出循环 带标签的continue和break 嵌套循环  深入continue ...

  5. Java 多线程(六) synchronized关键字详解

    多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchroniz ...

  6. Java中Volatile关键字详解

    一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...

  7. Java中Volatile关键字详解(转载)

    转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...

  8. Java中Volatile关键字详解 (转自郑州的文武)

    java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...

  9. 从线程池到synchronized关键字详解

    线程池 BlockingQueue synchronized volatile 前段时间看了一篇关于"一名3年工作经验的程序员应该具备的技能"文章,倍受打击.很多熟悉而又陌生的知识 ...

随机推荐

  1. bazel-demo2_1

    demo2_1目录树 ├── app │ ├── BUILD │ ├── hello_world.cpp │ └── lib │ ├── BUILD │ ├── func.cpp │ └── func ...

  2. 解决NSImage绘制的时候图像模糊

    Mac下NSImage绘制模糊的原因之一是draw到了非整数像素上,框架在渲染的时候就会模糊. 针对这一原因写了以下工具: /** * @brief 一劳永逸的解决NSImage绘制的时候绘到浮点值像 ...

  3. 用C++画光(一)——优化

    写在前面 在先前的画光系列中,实现实体几何.反射.折射等效果,但是最大的一个缺陷是复杂度太高.当采样是1024时,渲染时间直线上升(用4线程),以至好几个小时才能完成一副作品,实现太慢.然而,当我看到 ...

  4. Python中写一个乒乓球类的游戏

    最近开始学Python,感觉挺好玩的,既有脚本语言的灵活性,又有丰富的类库与面向对象的特点,开发起来很方便. 游戏的规则和乒乓球一样,如果妙蛙种子掉地上了就算输,你可以用蓝色的跷跷板弹它,使他不落到地 ...

  5. eclipse下properties配置文件中文乱码解决

    properties文件常带有中文注释,eclipse显示是乱码. 安装插件(properties editor)可以解决properties配置文件乱码的问题. 菜单 : Help->Ecli ...

  6. excel自定义函数添加和使用方法

    第一,excel自定义函数简介 Excel自带很多函数供使用,但有些问题用内置函数解决起来很复杂,甚至是无能为力,这时就可以利用VBA开发自定义函数. 第二,excel如何添加自定义函数 excel自 ...

  7. web编码

    1各种编码 A .1 html编码  -HTML标签 this.Response.Write(this.Server.HtmlEncode("<h1>的作用将文本设置为标题样式! ...

  8. win7共享文件夹设置无密码

    首先我们要启用guest账户,右键计算机 2 选择管理 3 选择本地用户和组 4 然后选择用户 5 然后选择Guest右键——属性——把账户已禁用勾掉,就可以了 6 然后点击桌面网络右键——属性 7 ...

  9. js 区分 safari chrome iso

    网上有很多这个文章的代码,但是在区分safari chrome 没有很好的例子,因为chrome包含了 safari 毕竟他们都是wekit内核,不过利用jquery还是能区分的 在这里分享下吧 -- ...

  10. 执行sql出现No Dialect mapping for JDBC type: -9错误

    name的数据类型是nvarchar吗?如果是改为varchar类型应该能运行,但是这个治标不治本,这是hibernate没映射nvarchar 刚才整理了一下varchar和nvarchar的区别, ...