在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. [转] 移动平台Html5的viewport使用经验

    转自:http://blog.csdn.net/wuruixn/article/details/8591989 问题描述 web页面采用html5技术实现,在系统登录页面中使用frameset.fra ...

  2. ios实现分发下载

    背景:原来公司Jenkins打包后的ipa和apk都是通过第三方的平台托管,手动上传,然后去扫二维码下载.虽然第三方平台有Jenkins插件来直接上传到该平台,但是想自己进行管理.所以就自己来做安装包 ...

  3. Element DatePicker日期范围选择

    前7天后7天 <el-date-picker v-model="value1" type="date" :picker-options="pic ...

  4. SQL Server判断数据库、表、存储过程、函数是否存在

    --判断数据库是否存在 if exists (select * from sys.databases where name = '数据库名') drop database [数据库名] --判断表是否 ...

  5. 解题报告-908. Smallest Range I

    题目 : Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <= K ...

  6. ubuntu开机执行指令或脚本

    vi /etc/rc.d/rc.localz 将指令添加到exit 0之前,保存.

  7. equals()方法左右变量的位置

    题:一个变量,一个常量,用equals()方法比较,让咱们,看看到底是常量放前面好啊,还是变量放前面好 ------------------------------------------------ ...

  8. nvidia 驱动下载地址

    http://www.nvidia.com/Download/index.aspx?lang=en-us

  9. 静态HTML服务器

    主要代码 #pragma once#include "pre.h"#include <thread> NAMESPACE(DEF) class Socket {publ ...

  10. Web图片编辑控件开发文档-Xproer.ImageEditor

    版权所有 2009-2014 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com 产品首页:http://www.ncmem.com/webplug/image-e ...