进行多线程编程的时候,需要考虑的是线程间的同步问题。对于共享的资源,需要进行互斥的访问。在Java中可以使用一些手段来达到线程同步的目的:

1. synchronized

2. ThreadLocal,线程本地变量

3. Java.util.concurrent.Lock

Java中,线程会共享堆上的实例变量以及方法区的类变量,而栈上的数据是私有的,不必进行保护。synchronized方法或synchronized块将标记一块监视区域,线程在进入该区域时,需要获得对象锁或类锁,JVM将自动上锁。synchronized提供了两种主要特性:

1. 互斥。互斥是指一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的并发访问,保证一次只有一个线程能够使用该共享数据。

2.可见性。确保释放锁之前对共享数据做出的更改对随后获得该锁的另一个线程是可见的。如果不能保证可见性,也就无法保证数据正确性,这将引发严重问题。volitail关键字同样保证了这种可见性。

在这里,我们将探讨synchronized使用时的三种情况:

1. 在对象上使用synchronized

2. 在普通成员方法上使用synchronized

3. 在静态成员方法上使用synchronized

这三种线程同步的表现有何不同?

下面通过三段示例代码来演示这三种情况。这里模拟线程报数的场景。

情况一:在普通成员函数上使用synchronized

public class MyThread extends Thread {

    public static void main(String[] args) throws Exception {
for (int i = 1; i < 100; i++) {
MyThread t = new MyThread();
t.setName("Thread="+i);
t.start();
Thread.sleep(100);
}
} @Override
public synchronized void run() {
for (int i = 1; i < 10000; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}

对一个成员函数使用synchronized进行加锁,所获取的锁,是方法所在对象本身的对象锁。在这里,每个线程都以自身的对象作为对象锁,要对线程进行同步,要求锁对象必须唯一,所以这里多个线程间同步失败。

情况二:在对象上使用synchronized

这里在类中增加一个成员变量lock,在该变量上使用synchronized:

public class MyThread1 extends Thread {

    private String lock;

    public MyThread1(String lock) {
this.lock = lock;
} public static void main(String[] args) throws Exception {
String lock = new String("lock");
for (int i = 1; i < 100; i++) {
Thread t = new MyThread1(lock);
t.setName("Thread=" + i);
t.start();
Thread.sleep(100);
}
} @Override
public void run() {
synchronized (lock) {
for (int i = 1; i < 10000; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}

100个线程在创建的时候,都传递了同一个lock对象(在main中创建的)去初始化线程类成员lock,因此,这100个线程都在同一个lock对象上进行synchronized同步。因此线程同步成功。

情况三:在静态成员函数上使用synchronized

public class MyThread2 extends Thread {

    public static void main(String[] args) throws Exception {

        for (int i = 1; i < 10; i++) {
Thread t = new MyThread2();
t.setName("Thread=" + i);
t.start();
Thread.sleep(10);
}
} public static synchronized void func() {
for (int i = 1; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
} @Override
public void run() {
func();
}
}

这种情况下,线程获得的锁是对象锁,而对象锁是唯一的,因此多个进程间也能同步成功。

补充:

1. 慎用字符串常量做同步对象,因为JVM内部会把常量字符串转换成同一个对象,同理的,基本数据除了Float和Double外,也有缓存对象[-128,127].

2. synchronized方法继承问题:1. 子类会继承父类的synchronized方法。2. 如果子类重写了父类的synchronized方法,必须也加上synchronized关键字,否则子类中的方法将变成非同步的。 3. 同一个子类对象中,子类的synchronized方法父类的synchronized方法使用的是同一个临界区。

(完)

  

Java锁机制(一)synchronized的更多相关文章

  1. java锁机制

    2.4 锁机制        临界区是指,使用同一个锁控制的同一段代码区或多段代码区之间,在同一时间内最多只能有一个线程在执行操作.这个概念与传统的临界区有略微的差别,这里不想强调这些概念上的差别,临 ...

  2. 转 : 深入解析Java锁机制

    深入解析Java锁机制 https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw%3D%3D&mid=2247485524&idx=1&s ...

  3. Java 锁机制总结

    锁的种类 独享锁 VS 共享锁 独享锁:锁只能被一个线程持有(synchronized) 共享锁:锁可以被多个程序所持有(读写锁) 乐观锁 VS 悲观锁 乐观锁:每次去拿数据的时候都乐观地认为别人不会 ...

  4. [转帖]B4. Concurrent JVM 锁机制(synchronized)

    B4. Concurrent JVM 锁机制(synchronized) https://www.cnblogs.com/zlxyt/p/11050346.html 挺好的 感觉这个文章写的 不过想要 ...

  5. Java锁机制深入理解

    Java锁机制 背景知识 指令流水线 ​ CPU的基本工作是执行存储的指令序列,即程序.程序的执行过程实际上是不断地取出指令.分析指令.执行指令的过程. ​ 几乎所有的冯•诺伊曼型计算机的CPU,其工 ...

  6. java锁机制的面试题

    java锁机制的面试题 1.ABA问题 2.CAS乐观锁 3.synchronize实现原理 4.synchronize与lock的区别 5.volatile实现原理 6.乐观锁的业务场景及实现方式 ...

  7. java 锁机制(synchronized 与 Lock)

    在java中,解决同步问题,很多时候都会使用到synchronized和Lock,这两者都是在多线程并发时候常使用的锁机制. synchronized是java中的一个关键字,也就是说是java内置的 ...

  8. Java 锁机制 synchronized

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/75126630 本文出自[赵彦军的博客] 1.前言 在多线程并发编程中Synchro ...

  9. JVM锁机制之synchronized

    概述: synchronized是java用于处理多线程同步的一个关键字,用于标记一个方法/代码块,使之成为同步方法/同步块. 用synchronized可以避免多线程处理时的竞态条件问题. 相关概念 ...

  10. Java锁机制了解一下

    前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 只有光头才能变强! 本文章主要讲的是Java多线程加锁机制,有两种: Synchro ...

随机推荐

  1. mysql时间加减运算

    一.MySQL 获得当前日期时间 函数 1.1 获得当前日期 + 时间(date + time) 函数:now() mysql> select now();+———————+| now() |+ ...

  2. [jzoj]1383.奇怪的问题

    Link https://jzoj.net/senior/#main/show/1383 Problem Alice总是会提出很多奇怪的问题,一天他让他的朋友Bob跟他一起研究一个奇怪的问题.问题是: ...

  3. app的创建和注册

    APP是用来存放代码的 创建APP 命令行创建,切换到项目目录下 python manage.py startapp appo1 #app01为项目名,创建完刷新即可 目录结构 把函数放到views后 ...

  4. SqlHelper分享

    using Model; using System; using System.Collections.Generic; using System.Configuration; using Syste ...

  5. 首席技术官应该考虑的网络安全问题 IT大咖说 - 大咖干货,不再错过

    首席技术官应该考虑的网络安全问题 IT大咖说 - 大咖干货,不再错过   http://www.itdks.com/dakalive/detail/5523

  6. JAVA:测试java虚拟机支持的最大内存 Xmx 值?Tomcat 内存溢出?(转)

    如下命令,即可测试:不断调整n的值,windows上32位的1.6x为: 1610m java -Xmx1610M -versionjava -Xmx1610m -version 网摘的tomcat内 ...

  7. RealTek WiFi 模块 RTL8710AF RTL8711AF RTL8711AM RTL8195AM

    瑞昱 8710 是一个完整且自成体系的 WiFi 网络解决方案, 能够独立运行,也可以作为从机搭载于其他主机 MCU 运行. 瑞昱 8710 在搭载应用并作为设备中唯⼀的应⽤处理器时,能够直接从外接闪 ...

  8. centOS --- 安装最新版的node nodejs

    对于 RHEL, CentOS or Fedora 系统,Node.js v8 LTS版本命令: curl –silent –location https://rpm.nodesource.com/s ...

  9. HTTPS之acme.sh申请证书

    1.关于let's encrypt和acme.sh的简介 1.1 let's encrypt Let's Encrypt是一个于2015年三季度推出的数字证书认证机构,旨在以自动化流程消除手动创建和安 ...

  10. 每天一个linux命令:top

    1.命令简介 top (top) 令经常用来实时监控linux的系统状况,比如cpu.内存的使用,类似于Windows的任务管理器. 2.用法 top -hv | -abcHimMsS -d dela ...