进行多线程编程的时候,需要考虑的是线程间的同步问题。对于共享的资源,需要进行互斥的访问。在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. CQD(陈丹琦)分治 & 整体二分——专题小结

    整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料:       整体二分是个很神的东西 ...

  2. 快速排序 [Qsort]

    在做USACO1.4 等差数列的时候,我发现如果用结构体+sort就会超时,用二维数组+qsort就能AC,所以为了不忘记Quick Sort,我还是把代码贴出来以备以后要看吧. void qsort ...

  3. Java 装饰模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述装饰(Decorator)模式的: 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替 ...

  4. 浅析js中2个等号与3个等号的区别(转)

    首先,== equality 等同,=== identity 恒等. ==, 两边值类型不同的时候,要先进行类型转换,再比较. ===,不做类型转换,类型不同的一定不等. 下面分别说明: 先说 === ...

  5. REST风格的增删改查(2)

    一.源码 1.页面 index.jsp <a href="emps">List All Employee</a> <br><br> ...

  6. Servlet(7)—ServletConfig接口和SevletContext接口

    ServletConfig接口 1. 可以获取当前Servlet在web.xml中的配置信息(用的不多) 2. 在不使用"硬编码"的情况下,将部署状态信息传递给Servlet.这个 ...

  7. MUI学习04-开关按钮

    HTML代码如下: <div class="mui-switch"> <div class="mui-switch-handle">&l ...

  8. CSS 埋点统计

    原文地址: https://my.oschina.net/u/1778933/blog/1608904 CSS 埋点统计 当一个网站或者 App 的规模达到一定程度,需要分析用户在 App 或者网站的 ...

  9. java利用Tesseract 识别身份证号码

    安装Tesseract http://blog.csdn.net/hiredme/article/details/50894814 http://blog.csdn.net/yoara/article ...

  10. Net Core 的配置模式以及热重载配置

    https://www.cnblogs.com/Leo_wl/p/8527535.html https://blog.csdn.net/ma_jiang/article/details/5350198 ...