[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 同步语句块

时间: 2024-11-03 23:45:13

[java] java synchronized 关键字详解的相关文章

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

Java 多线程(六) synchronized关键字详解 多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchronized关键字修饰一个方法的时候,该方法叫做同步方法. 当synchronized方法执行完或发生异常时,会自动释放锁. 下面通过一个例子来对synchronized关键字的用法进行解析. 1.是否使用synchronized关键字的不同 例子

Java synchronized 关键字详解

Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 synchronized public void sync(){ } 修饰静态成员方法 synchronized public static void sync(){ } 类锁代码块 synchronized (类.class){ } 对象锁代码块 synchronized (this|对象){ } syn

synchronized关键字详解

1.    把synchronized当作函数修饰符时,示例代码如下:public synchronized void method(){//-.}这也就是同步方法,那这时synchronized锁定的是哪个对象呢?他锁定的是调用这个同步方法对象.也就是说,当一个对象P1在不同的线程中执行这个同步方法时,他们之间会出现阻塞,达到同步的效果.但是这个对象所属的Class所产生的另一对象P2却能够任意调用这个被加了synchronized关键字的方法. 2.同步块,示例代码如下:public voi

JAVA几个关键字详解

本篇旨在帮助准备学习Java以及刚接触Java的朋友认识.掌握和使用static.this.super.final这几个关键字的使用.Java博大精深,我也是一位正在学习和使用Java的爱好者,文中难免有不妥之处,欢迎指正.一.static请先看下面这段程序:public class Hello{???? public static void main(String[] args){//(1)????????? System.out.println("Hello,world!");//

synchronized关键字详解(二)

synchronized关键字的性质 1.可重入:同一线程的外层函数获得锁之后,内层函数可直接再次获得该锁,好处:避免死锁,提升封装性 证明可重入粒度:1.同一个方法是可重入的 2.可重入不要求是同一个方法 3.可重入不要求是同一个类 可重入原理:加锁次数计数器 JVM负责跟踪对象被加锁的次数: 线程第一次给对象加锁的时候计数变为1,每当这个相同的线程在这个对象上加锁时,计数递增: 每当任务离开时,计数会减1,计数为0时,锁被完全释放. 2.不可中断:如果一个线程拿到一把锁,另一个线程要想获得这

Java中Volatile关键字详解

一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情.为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.也就是一个线程修改的结果.另一个线程马上就能看到.比如:用volatile修饰的变量,就会具有可见性.volatile修饰的变量不允许线程

java关键字详解

Java关键字及其作用 目录 Java关键字及其作用--- 1 一.     关键字总览:2 二.     详细解释--- 3 1.访问控制--- 3 1)私有的-- 3      private 2)受保护的-- 3      protected 3)公共的-- 3      public 2.类.方法和变量修饰符--- 3 1)声明抽象-- 3      abstract 2)类-- 4      class 3)继承.扩展-- 4      extends 4)最终.不可改变-- 4   

“全栈2019”Java异常第九章:throws关键字详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异常第九章:throws关键字详解 下一章 "全栈2019"Java异常第十章:throw与throws区别详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Ja

java中static作用详解

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被类的所有实例共享. 只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们.因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象. 用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类