进行多线程编程的时候,需要考虑的是线程间的同步问题。对于共享的资源,需要进行互斥的访问。在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. 编程菜鸟的日记-初学尝试编程-C++ Primer Plus 第5章编程练习2

    #include <iostream>using namespace std;const int MAXSIZE=100;int main(){ int a[MAXSIZE]; int s ...

  2. Yii2 组件

    组件的命名空间: 响应组件: yii\web\Response Yii预定义的HTTP异常组件: yii\web\BadRequestHttpException: //状态码 400. yii\web ...

  3. Kafka监控框架介绍

    前段时间在想Kafka怎么监控.怎么知道生产的消息或消费的消费是否有丢失,目前有几个开源的Kafka监控框架这里整理了下,不过这几个框架都有各自的问题侧重点不一样: 1.Kafka Monitor 2 ...

  4. drawRect中抗锯齿

    在开始之前,我们需要创建一个DrawRectView 其初始代码为 // // DrawRectView.h // CGContextSetShouldAntialias // // Created ...

  5. Spark2.2出现异常:ERROR SparkUI: Failed to bind SparkUI

    详细错误信息如下: // :: INFO util.log: Logging initialized @5402ms // :: INFO server.Server: jetty-9.3.z-SNA ...

  6. SSE图像算法优化系列二十五:二值图像的Euclidean distance map(EDM)特征图计算及其优化。

    Euclidean distance map(EDM)这个概念可能听过的人也很少,其主要是用在二值图像中,作为一个很有效的中间处理手段存在.一般的处理都是将灰度图处理成二值图或者一个二值图处理成另外一 ...

  7. Linux中添加计划任务与Elasticsearch日志自动清理

    一.简述 当日志发送到ELK之后,Elasticsearch随着日志的增加,占用磁盘量会越来越大.这时候,需要我们写角本定期DELETE日志.角本写法,也很简单,只是发送HTTP的DELETE方式到: ...

  8. IIS 重写 HTTP 重定向到 HTTPS

    1.购买SSL证书 2.IIS7 / IIS 7.5 下绑定 HTTPS 网站(购买Wildcard SSL泛域名证书可绑定多个子域名)参考上文 3.下载安装URL重写模块:Microsoft URL ...

  9. 全面理解Java内存模型(JMM)及volatile关键字(转载)

    关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...

  10. Python之关于量化投资实现代码--根据策略提出的代码--还未完善

    # 根据缺口的模式选股买股票 ''' -------------------------------------------- 1.总体回测前要做的事情 initialize(context) 1.1 ...