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. c++11特性与cocos2d-x 3.0之std::bind与std::function

    昨天同事让帮忙写一小功能,才发现cocos2d-x 3.0 和 cocos2d-x 3.0rc0 差别还是相当大的. 发现Label这一个控件,3.0就比rc0版本多了一个创建函数,更为关键的是3.0 ...

  2. NIS & Kerberos配置

    NIS & Kerberos配置 所需RPM包列表: krb5-server-1.10.3-42.el6.x86_64.rpm krb5-workstation-1.10.3-42.el6.x ...

  3. java 日期获取时间戳

    SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");            String dateS ...

  4. c++之五谷杂粮---3

    3.1如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数. 3.1.1不允许两个函数除了返回类型外所有的要素都相同.(这也是很好解释的) #include<iostream&g ...

  5. bootstrap内容太多表格撑破

    增加样式  style="word-break:break-all; word-wrap:break-all;" 这样内容就会自动换行,表格就美观多了. <table cla ...

  6. I/O限制异步操作

    CLR非异步操作读取文件的过程图 非异步操作主要是因为每次请求硬件如(硬盘,网卡等)的线程都处于阻塞状态,导致以后的请求都需要重新创建新的线程.导致线程上下文的切换频繁. 异步IO操作主要是通过每次的 ...

  7. Pro mvvm读书笔记mvvm中的VM

    一.构建ViewModels 设计模式的其中一个目标就是抽象构造一个给出指定类型的对象或者实现指定类型的接口的过程.需要把类给客户端,让客户端去使用,但是要隐藏类是具体的实现细节. 1.1The Ap ...

  8. 中断线程详解(Interrupt)

    在上篇文章<多线程的使用——Thread类和Runnable接口>中提到中断线程的问题.在JAVA中,曾经使用stop方法来停止线程,然而,该方法具有固有的不安全性,因而已经被抛弃(Dep ...

  9. 【C】——指针与const限定符

    const限定符和指针结合起来常见的情况有以下几种. const int *a; int const *a; 这两种写法是一样的,a是一个指向const int型的指针,a所指向的内存单元不可改写,所 ...

  10. 时间控件 BeatPicker

    项目展示 样式异样,可修改此样式,详见官网:https://github.com/ACT1GMR/BeatPicker --- 开始使用 1.引入js&css文件 <link rel=& ...