在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法。

因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识。

java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的

若一个非抽象类实现一个接口,就必须重写接口中所有的方法,所以你实现Runnable接口时,会重写run()方法,run()方法只是把该线程编程可就绪状态,start()方法是将该线程变为可运行状态,好好理解下。。。

误区一:synchronized关键字只能用在实现Runnable或者继承了Thread类的子类的方法里面。

正解:如果有一块代码(或方法)可能被多个线程同时访问,然后里面操作的数据修改操作可能因为不同线程的操作而不一致的时候,使用synchronized锁定这块代码,确保同时只有一个线程访问这个代码块。也就是说,关键字synchronized可以用在任何类的方法里面,即使该类没有实现Runnable接口或者继承Thread类。

误区二:synchronized(this)和synchronized(object)作用范围完全不同。

正解:当多个线程访问同一个类 A 的方法 A() 的时候。并且,这个方法 A() ,要求一个线程执行完了之后再给另外一个线程去执行。那么,这个方法 A() 就必须加上 synchronized 关键字,或者,在该方法 A() 中写上

synchronized(this//指代当前类A的实例) { }

如果不在声明方法 A() 时,加上 synchronized 关键字,或者,不在方法 A() 中加上 synchronized(this){ }
同步块的时候可以在线程类的 run() 方法内

synchronized(Object //指代类A的实例){
 Object.A();
}
实现多线程同时有序访问该同步块内类 A 的方法 A() 的目的。

object本身就包含this的情况。

this 指代的是当前同步块所在方法所在的类,当不需要引用别的类的时候。

object 指代的是需要调用的类,引用了别的类,且需要处理多线程并发访问时,object 指代的是被引用的类。如果没有引用别的类,则指代的就是同步块所在方法所在的类本身

一般来说,一个方法处理的内容很多,如果synchronized修饰以后,其他同步方法就必须等待其执行完毕才可以继续执行,如果该方法需要较长时间处理,这就明显会降低效率,失去了多线程的意义,所以我们可以考虑将同步的范围缩小,即从同步一个方法缩小为同步一段代码块,这就是同步代码块产生的原因。同步代码块的语法是:

synchronized (this) {}
synchronized (object) {}

synchronized(this)我称之为this同步代码块,针对的是当前对象;synchronized(object)我称之为非this同步代码块,针对的是object对象。

记住一点即可:不论是同步方法还是同步代码块,实质上都是争夺锁的问题,而锁一定是对象级的,即一个对象只会产生一个锁,所以只要有一个线程在执行synchronized修饰的东西(不论是方法还是代码块),那么其他线程都无法访问被synchronized修饰的方法或代码块。
但是注意使用非this同步代码块的时候,里面的object不要用String类型的,因为大家都知道JVM具有String常量池缓存的功能,所以使用String类型可能产生问题。

下面用一个栗子来区分同步方法还有同步代码块的synchronized (this)和synchronized (object)

MethodSync 方法

例如 :

public class MethodSync{
private String anyString; public MultiSyn(String anyString) {
this.anyString = anyString;
}

/*
* 同步类方法
* @Task : 测试 synchronized 修饰方法时锁定的是调用该方法的对象
* @param name 线程的标记名称
*/
public synchronized void method(String name){
System.out.println(name + " Start a sync method");
try{
Thread.sleep(300);
}catch(InterruptedException e){}
System.out.println(name + " End the sync method");
} /**
* 同步代码块
* @param name
*/
public void asyncMethod(String name){
synchronized (MethodSync.class){
try {
System.out.println("同步代码块!!!!"+name);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(name + " End the sync method");
}
}
}
/**
* 非this同步代码块
*/
public void synObject() {
synchronized (anyString) {
System.out.println(anyString + " IN synchronized (anyString)同步代码块");
System.out.println(anyString + " OUT synchronized (anyString)同步代码块");
}
}
}

RunnableService 调用

public class RunnableService implements Runnable {

    /**
* 一、
* test1 先于 test2 执行 同步方法,但是却后于 test2 结束。这里并没有达到互斥的效果!
* 原因是:MethodSync是实例变量,每次创建一个Test对象就会创建一个MethodSync对象,
* synchronized 只会锁定调用method()方法的那个MethodSync对象,
* 而这里创建的两个线程分别拥有两个不同的MethodSync对象,它们调用method方法时就没有互斥关系。
*
*/ /**
* 二、
* 当把Test.java 中的MethodSync 变量 用 static 来修饰时,执行结果如下:
* 这里,正确实现了同步作用。原因如下:这里也创建了二个线程(Test 对象),
* 但是每个Test对象共享MethodSync 变量,也即只有一个MethodSync 变量在两个线程中执行 method方法,
* 这样两个线程在执行到method 方法这段代码时就会形成互斥
*
*/ private String name; private static MethodSync methodSync = new MethodSync();
// private MethodSync methodSync = new MethodSync(); public RunnableService(String name){
this.name = name;
} /**
* run方法它本身启动不了多线程。多线程在实现的时候看着只是重写run方法
* ,调用start方法启动,其实start方法里边还有其它操作:创建线程,调用run方法。
*/
@Override
public void run() {
methodSync.method(name);
} public static void main(String[] args) {
// MethodSync methodSync = new MethodSync();
// methodSync.method("你好1");
// methodSync.method("你好2");
Thread t1 = new Thread(new RunnableService("test 1"));
Thread t2 = new Thread(new RunnableService("test 2"));
t1.start();
t2.start(); } }

打印日志

test 1 Start a sync method
test 1 End the sync method
test 2 Start a sync method
test 2 End the sync method Process finished with exit code 0

代码 : https://gitee.com/xdymemory00/AsyncWithLock.git

继承Runnable 实现Synchronized 同步锁的更多相关文章

  1. Java进程与多线程+线程中的join、yield、wait等方法+synchronized同步锁使用

    首先了解什么是多线程与进程 进程:是一个执行过程,动态的概念 --->会分配内存线程:是进程的一个单元,线程是系统最小的执行单元 详解: http://blog.csdn.net/luoweif ...

  2. Java中String做为synchronized同步锁使用详解

    Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...

  3. 深入研究 synchronized 同步锁 作用于 静态方法 和 非静态方法 的 区别

    1.前言 众所周知, synchronized 是同步锁 ,虽然在底层又细分了无锁.偏向锁.轻量级锁.自旋锁 以及重量级锁 机制, 这些底层锁知道一下原理即可 ,[想要 了解 这篇 博文 有 解释 : ...

  4. synchronized同步锁

    在多线程的情况下,由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问.由于 ...

  5. 三、synchronized同步锁

    一.简介 在Java多线程中,我们要实现同步串行最早接触的就是synchronized关键字. 基本语法如下: synchronized(锁) { // 代码块 } sychronized关键字的锁主 ...

  6. 2.synchronized同步锁

    原文链接:http://blog.csdn.net/zteny/article/details/54863391 简介 synchronized是Java语言的一个关键字,用来修饰一个方法或者代码块, ...

  7. synchronized同步锁+单利模式

    public static synchronized VolleyRequestController getInstance() {         if (sInstance == null) { ...

  8. Java中String做为synchronized同步锁

    synchronized (("" + userId).intern()) { // TODO:something } JVM内存区域里面有一块常量池,关于常量池的分配: JDK6 ...

  9. synchronized同步代码块锁释放

    今天发现自己写的线上程序出现数据库不能同步的问题,查看日志已经停止记录,随后使用jstack查看线程的运行状况,发现有个同步线程锁住了. 以下是jstack -l 637  问题线程的内容. &quo ...

随机推荐

  1. 启动JAR Hadoop任务

    [启动JAR Hadoop任务] 一般情况下,我们会使用下面的命令来运行一个hadoop任务: 这个命令实际上是转化成下面的命令来运行的 在RunJar中,会读取abc.jar文件,然后尝试从mani ...

  2. ThinkPHP出现General error: 2006 MySQL server has gone away的解决方法

    错误: #13 {main}SQLSTATE[HY000]: General error: 2006 MySQL server has gone awayFILE: \ThinkPHP\Library ...

  3. Git学习笔记-----下载GitHub上某个分支的代码

    在GitHub上的仓库里,往往建有几个分支,如果只是想下载某个分支的代码,怎么办呢? 1.需要知道远程分支的名称,及远程分支所在的Git仓库 2.按下面指令下载 git clone -b 远程分支名称 ...

  4. Efficient algorithms for polyploid haplotype phasing 多倍体单体型分型的有效算法

    背景:单倍型的推断,或沿着相同染色体的等位基因序列,是遗传学中的基本问题,并且是许多分析的关键组分,包括混合物图谱,通过下降和插补识别身份区域. 基于测序读数的单倍型定相引起了很多关注. 已经广泛研究 ...

  5. 如何规范移动应用交互设计?UI/UX设计师须知的11个小技巧

    以下内容由Mockplus团队翻译整理,仅供学习交流,Mockplus是更快更简单的原型设计工具. 十年前,手机的使用只是为了沟通. 而近几年,情况发生了很大变化,我们很难找到不使用手机的人.手机在极 ...

  6. 两个openssh间免密码登录

    以下针对的是openssh,而不是ssh,也不是ssh2.配置分两部分:一是对登录机的配置,二是对被登录机的配置,其中登录机为客户端,被登录机为服务端,也就是解决客户端到服务端的无密码登录问题.下述涉 ...

  7. 微信公众开发URL和token填写详解

    微信公众开发URL和token填写详解 方法/步骤     作为一名微信公众号开发者,别人进入你的微信公众号,肯定会看见某些网页,或者给你发某些信息,你需要实时自动回复,所以你需要一个24小时为用户服 ...

  8. Tempdb--monitoring and troubleshooting

    TempDB用来存放临时表.全局临时表.表变量以及排序或HASH等操作引发的中间结果集 TempDB在每次实例重启时重新创建,TempDB数据库文件的初始化大小取决于Model数据库的文件大小或显示A ...

  9. 构建命令maven install 打包不是最新的代码

    问题: 之前一直用的是mvn install 命令来构建项目,但是最近发现最新的代码没有在war包中.之前看的说 mvn install 命令会执行之前的所有阶段,会被编译,测试,打包. 经查最后采用 ...

  10. maven多模块启动required a bean of type com.xxx.xxx.service that could not be found.

    Description: Field testService in com.xxx.xxx.api.controller.TestController required a bean of type ...