在JAVA多线程编程中,将需要并发执行的代码放在Thread类的run方法里面,然后创建多个Thread类的对象,调用start()方法,线程启动执行。

当某段代码需要互斥时,可以用 synchronized 关键字修饰,这里讨论 synchronized 关键字修饰方法时,是如何互斥的。

synchronized 修饰方法时锁定的是调用该方法的对象。它并不能使调用该方法的多个对象在执行顺序上互斥。

下面举个具体的例子说明:

Test.java 通过 implements Runnable 成为一个线程类,它有一个MethodSync实例变量,这样,每当实例化一个Test对象时(相当于创建一个线程)就会初始化一个相应的MethodSync对象。然后在Test类的run()方法里面调用 synchronized 修饰的方法。

Test.java

 public class Test implements Runnable{
private String name;
// private static MethodSync methodSync = new MethodSync();
private MethodSync methodSync = new MethodSync(); public Test(String name){
this.name = name;
} @Override
public void run() {
methodSync.method(name);
} public static void main(String[] args) {
Thread t1 = new Thread(new Test("test 1"));
Thread t2 = new Thread(new Test("test 2"));
t1.start();
t2.start();
}
}

上面创建了二个Test类的对象,相当于启动了两个线程, 这两个线程将会并发地执行它们的run方法中的代码。

MethodSync.java ,该类只拥有一个用来测试的 synchronized 方法

 public class MethodSync {

     /*
* @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");
}
}

先看执行结果:

test1 先于 test2 执行 同步方法,但是却后于 test2 结束。这里并没有达到互斥的效果!原因是:MethodSync是实例变量,每次创建一个Test对象就会创建一个MethodSync对象, synchronized 只会锁定调用method()方法的那个MethodSync对象,而这里创建的两个线程分别拥有两个不同的MethodSync对象,它们调用method方法时就没有互斥关系。

当把Test.java 中的MethodSync 变量 用 static 来修饰时,执行结果如下:

这里,正确实现了同步作用。原因如下:这里也创建了二个线程(Test 对象),但是每个Test对象共享MethodSync 变量,也即只有一个MethodSync 变量在两个线程中执行 method方法,这样两个线程在执行到method 方法这段代码时就会形成互斥。

2018.12.13更新:

记录一下我对synchronized关键字的理解:

1,相对于ReentrantLock而言,synchronized锁是重量级锁,重量级体现在活跃性差一点。synchronized锁是内置锁,意味着JVM能基于synchronized锁做一些优化:比如增加锁的粒度(锁粗化)、锁消除。

2,在synchronized锁上阻塞的线程是不可中断的:线程A获得了synchronized锁,当线程B也去获取synchronized锁时会被阻塞。而且,线程B无法被其他线程中断(不可中断的阻塞),而ReentrantLock锁能实现可中断的阻塞。

3,synchronized锁释放是自动的,当线程执行退出synchronized锁保护的同步代码块时,会自动释放synchronized锁。而ReentrantLock需要显示地释放:即在try-finally块中释放锁。

4,线程在竞争synchronized锁时是非公平的:假设synchronized锁目前被线程A占有,线程B请求锁未果,被放入队列中,线程C请求锁未果,也被 放入队列中,线程D也来请求锁,恰好此时线程A将锁释放了,那么线程D将跳过队列中所有的等待线程(即:线程B和线程C)并获得这个锁。

而ReentrantLock能够实现锁的公平性。

5,synchronized锁是读写互斥并且 读读也互斥,ReentrantReadWriteLock 分为读锁和写锁,而读锁可以同时被多个线程持有,适合于读多写少场景的并发。

JAVA 同步之 synchronized 修饰方法的更多相关文章

  1. java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?

    wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...

  2. synchronized修饰方法和对象的区别

    使用synchronized(object) { 代码块.... } 能对代码块进行加锁,不允许其他线程访问,其的作用原理是:在object内有一个变量,当有线程进入时,判断是否为0,如果为0,表示可 ...

  3. 关于java线程锁synchronized修饰普通方法与静态方法的区别

    最近研究线程方面问题,关于这个synchronized锁修饰的问题,先是修饰普通方法,然后通过两个线程,各自执行自己对象的锁,发现方法执行互不影响,代码如下: private static int n ...

  4. 一张图讲解对象锁和关键字synchronized修饰方法

    每个对象在出生的时候就有一把钥匙(监视器),那么被synchronized 修饰的方法相当于给方法加了一个锁,这个方法就可以进行同步,在多线程的时候,不会出现线程安全问题. 下面通过一张图片进行讲解: ...

  5. java同步代码(synchronized)中使用BlockingQueue

    说起BlockingQueue,大家最熟悉的就是生产者-消费者模式下的应用.但是如果在调用queue的上层代码加了同步块就会导致线程死锁. 例如: static BlockingQueue<St ...

  6. java基础之synchronized使用方法

    首先.參考文章:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html PS:參考文章非常长,但内容非常丰富,若是刚開始学习 ...

  7. synchronized修饰方法和代码块的区别

    先看一段代码 Class A { public synchronized methodA() {//对当前对象加锁 } public methodB() { synchronized(this){}/ ...

  8. Java中synchronized 修饰在static方法和非static方法的区别

    [问题描述]关于Java中synchronized 用在实例方法和对象方法上面的区别 [问题分析]大家都知道,在Java中,synchronized 是用来表示同步的,我们可以synchronized ...

  9. JAVA之线程同步的三种方法

    最近接触到一个图片加载的项目,其中有声明到的线程池等资源需要在系统中线程共享,所以就去研究了一下线程同步的知识,总结了三种常用的线程同步的方法,特来与大家分享一下.这三种方法分别是:synchroni ...

随机推荐

  1. Spring Boot系列——日志配置

    日志,通常不会在需求阶段作为一个功能单独提出来,也不会在产品方案中看到它的细节.但是,这丝毫不影响它在任何一个系统中的重要的地位. 为了保证服务的高可用,发现问题一定要即使,解决问题一定要迅速,所以生 ...

  2. Linux Shell 运算符

    Shell 和其他编程语言一样,支持多种运算符,包括: 算数运算符 关系运算符 布尔运算符 逻辑运算符 字符串运算符 文件测试运算符 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 ...

  3. Vmware 虚拟机无法启动

    问题背景: 自己的电脑坏了,用的事小伙伴的电脑,安装VMware 软件,然后创建虚拟机(放在移动硬盘上).在操作虚拟主机的时候,中间不小心碰到了移动硬盘, 然后移动硬盘就掉线了.这个时候再去启动虚拟主 ...

  4. Spring Boot 2.x 学习专栏

    Spring Boot 2.0 入门指南 Spring Boot 2.0 返回JSP页面实战 Spring Boot 2.0 热部署指南 Spring Boot 2.0 整合FreeMarker模板引 ...

  5. C#中,重新排列panel中的按钮

    https://www.cnblogs.com/hfzsjz/archive/2010/08/13/1799068.html void ArrangeButtons(Panel pn) { , y = ...

  6. Android jks 签名文件 生成

    Android Win7 上使用cmd生成Jks cmd 命令 C:\Program Files\Java\jre1.8.0_111\bin>keytool -genkeypair -alias ...

  7. PHPStorm + Homestead + Xdebug + Chrome Xdebug Helper 调试配置

    话说 PHPStorm 写起代码来非常带感,各种提示补全和纠错,以及在 L5 中的命名空间功能更是强大到感动(新建类自动添加命名空间,自动引入命名空间,返回参数命名空间纠正等等).当然它的调试功能更是 ...

  8. 测试创建表变量对IO的影响

    测试创建表变量前后,tempdb的空间大小,目前使用sp_spaceused得到大小,也可以使用视图sys.dm_db_file_space_usage use tempdb go Set nocou ...

  9. vs code 设置问题

    现已取消 .vue 文件与 HTML 的默认关联,需要手动配置.vue 文件里不能使用div + Tab 键快速生成 html 代码   "emmet.syntaxProfiles" ...

  10. zookeeper入门及使用(二)- 状态查看

    查看服务的角色,看Mode字段,有follower及leader [root@c7bit1 bin]# echo stat | nc 127.0.0.1 2181 Zookeeper version: ...