为了确保可以在线程之间以受控方式共享数据,Java 语言提供了两个关键字:synchronized 和volatile。
Synchronized 有两个重要含义:它确保了一次只有一个线程可以执行代码的受保护部分(互斥,mutual exclusion 或者说 mutex),而且它确保了一个线程更改的数据对于其它线程是可见的(更改的可见性)。
Volatile 比同步更简单,只适合于控制对基本变量(整数、布尔变量等)的单个实例的访问。当一个变量被声明成 volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主内存,而任何对该变量的读取也都绕过高速缓存,直接取自主内存。这表示所有线程在任何时候看到的 volatile 变量值都相同。
Synchronized :
每个 Java 对象都有一个相关的锁。同一时间只能有一个线程持有 Java 锁。当线程进入 synchronized 代码块时,线程会阻塞并等待,直到锁可用,当它可用时,就会获得这个锁,然后执行代码块。当控制退出受保护的代码块时,即到达了代码块末尾或者抛出了没有在 synchronized 块中捕获的异常时,它就会释放该锁。
需要注意的是,无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁。但即使一个 Java 对象的锁正被其他线程占用时,仍可访问这个对象中没有 synchronized 修饰的代码块。
假设多个线程共享一个计数器,如下:
public class Counter {
private int counter = 0;
public int get() { return counter; }
public void set(int n) { counter = n; }
public void increment() {
set(get() + 1);
}
}
要使递增操作正确运行,不仅get() 和 set() 必须是 synchronized,而且 increment() 也必需是synchronized!否则,调用 increment() 的线程可能会中断另一个调用 increment() 的线程。如果不走运,最终结果将会是计数器只增加了一次,不是两次。同步 increment() 防止了这种情况的发生,因为整个递增操作是原子的。
synchronized作用于方法时,锁定的是调用这个同步方法对象。当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
public class TestSynchronized extends Thread{
public synchronized void method(){
System.out.println(this.currentThread().getName() + " - method() begin");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.currentThread().getName() + " - method() over");
}
public void run() {
method();
}
public static void main(String[] args) {
/*
* 同一个对象:
* 当同一个对象在不同的线程中,执行一个同步方法时,它们之间会形成互斥,达到同步的效果
*/
TestSynchronized ts = new TestSynchronized();
Thread t1 = new Thread(ts);
Thread t2 = new Thread(ts);
t1.start();
t2.start();
/*
* 不同的对象:
* 当同一个Class产生的不同对象在不同的线程中执行一个同步方法时,
* 他们可以任意调用这个被加了synchronized关键字的方法,而互不影响,不形成互斥,达不到同步效果。
* 也就是说此时synchronized并未起到任何作用,与不加这个关键字效果是一样的。
*
TestSynchronized ts1 = new TestSynchronized();
TestSynchronized ts2 = new TestSynchronized();
Thread t1 = new Thread(ts1);
Thread t2 = new Thread(ts2);
t1.start();
t2.start();
*/
}
}
同一个对象的运行结果:
Thread-1 - method() begin
Thread-1 - method() over
Thread-2 - method() begin
Thread-2 - method() over
不同的对象的运行结果:
Thread-1 - method() begin
Thread-2 - method() begin
Thread-1 - method() over
Thread-2 - method() over
其中,
public synchronized void method(){
......
}
相当于
public synchronized void method(){
synchronized (this){ //this指的就是调用这个方法的对象
......
}
}
synchronized作用于同步块时,示例代码如下:
public void method(SomeObject so)
{
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void method()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
分享到:
相关推荐
Java线程:线程的同步 33 一、 同步方法 35 二、 同步块 36 三、 volatile关键字 38 四、 使用synchronized关键字要注意以下四点 39 五、 关于同步和锁定的一些问题 41 Java线程:并发协作-线程的交互 47 Java线程:...
Java分布式应用学习笔记05多线程下的并发同步器
{1}Java基础}{17}{chapter.1} {1.1}基本语法}{17}{section.1.1} {1.2}数字表达方式}{17}{section.1.2} {1.3}补码}{19}{section.1.3} {1.3.1}总结}{23}{subsection.1.3.1} {1.4}数据类型}{23}{section.1.4} {...
线程的基本概念 线程的创建和启动 线程的调度和优先级 线程的状态控制 线程同步
java核心技术-多线程的概念及多线程单例设计模式的应用-懒汉模式、饿汉模式、优化懒汉
Java分布式应用学习笔记03JVM对线程的资源同步和交互机制
java分布式应用学习笔记05多线程下的并发同步器.pdf
学习目录:1. 线程简介 2. 线程实现(重点) 3. 线程状态 4. 线程同步(重点) 5. 线程通信问题 6. 高级主题
本书内容非常全面,涵盖了《Java编程思想》、《Java学习笔记》等书籍所有知识要点,并结合作者自己经验总结而编写,内容丰富程度胜过一切书籍 众所周知,一般书籍为了销售需要,往往很少的知识点,却需要添加大量的...
JUC(Java Util Concurrent)是Java中用于并发编程的工具包,提供了一组接口和类,用于处理多线程和并发操作。JUC提供了一些常用的并发编程模式和工具,如线程池、并发集合、原子操作等。 JUC的主要特点包括: ...
主要为大家详细介绍了java struts2学习笔记之线程安全,感兴趣的朋友可以参考一下
(2)建模简单:通过使用线程可以讲复杂并且异步的工作流进一步分解成一组简单并且同步的工作流,每个工作流在一个单独的线程中运行,并在特定的同步位置交互 (3)简化异步事件的处理:服务器应用程序在接受...
Java并发编程学习笔记 本项目整理自《Java7并发编程实战手册》,感兴趣的话推荐阅读原著 本章内容包括: 线程的创建和运行 线程信息的获取和设置 线程的中断 线程中断的控制 线程的Hibernate和恢复 等待线程的终止 ...
作者: 原文地址: ...而线程共享所属进程占有的内存地址空间和资源,数据共享简单,但是同步复杂。 进程单独占有一定的内存地址空间,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠
第一次校验的时候没有同步锁,如果已经实例化了,直接返回即可,省下了同步锁要消耗的资源 第二次校验是因为第一次校验没有同步锁,所以多个线程都可能进入,同步块内二重
[Java多线程核心编程技术] 书籍笔记 第一章:Java多线程技能 线程是进程中的子任务 interrupted与isInterrupted的区别: interrupted是Thread类的静态方法,里面调用了isTnterrupted方法[currentThread().isInterrupted...
基于java的基础知识,进行归纳的文件,包括基本语法和高级语法,如:5 线程 同步异步 Lambda,7 函数式接口 stream流 反射等。以及部分案例
000000_【课程介绍 —— 写在前面的话】_Java学习概述笔记.pdf 010101_【第1章:JAVA概述及开发环境搭建】_JAVA发展概述笔记.pdf 010102_【第1章:JAVA概述及开发环境搭建】_Java开发环境搭建笔记.pdf 010201_【第2...
Thread [java] 线程 [θred] throw (关键字) throws (关键字) [θrәu] 抛出(异常) transient (关键字) 瞬变;临时的['trænziәnt]'(可序列化) valid 正确的,有效的 ['vælid] variable n.变量 a.可变的['vєә...