为了确保可以在线程之间以受控方式共享数据,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 线程学习笔记 Java 线程创建有两种方法: 1. 继承 Thread 类,重写 run 方法:通过继承 Thread 类并重写 run 方法来创建线程,这种方法可以使线程具有自己的执行逻辑。 2. 实现 Runnable 接口:通过实现 ...
这篇学习笔记将深入探讨Java多线程的核心概念、实现方式以及相关工具的使用。 一、多线程基础 1. 线程与进程:在操作系统中,进程是资源分配的基本单位,而线程是程序执行的基本单位。每个进程至少有一个主线程,...
【Java学习笔记】 在Java的学习旅程中,深入理解其核心概念是至关重要的。Java是一种广泛使用的面向对象的编程语言,以其跨平台性、高效性和稳定性而受到青睐。本笔记集合将带你逐步走进Java的世界,从基础语法到...
这份"java学习笔记-初学者的福音"涵盖了从基础到进阶的多种概念,旨在帮助初学者系统地掌握Java编程。 首先,Java的基础部分包括语法结构。Java是一种面向对象的语言,这意味着它将数据和操作数据的方法封装在类中...
这份"2022年Java学习笔记-Java课程配套案例.rar"压缩包文件显然是为了帮助学习者深入理解Java编程,通过实践案例来巩固理论知识。下面将详细探讨Java语言的一些核心知识点,并结合压缩包中的案例进行说明。 1. **...
多线程学习笔记 iOS开发中,多线程是一种常见的技术手段,用于优化应用程序的性能,提升用户体验。多线程的核心是让程序能够并发地执行多个任务,合理地利用设备的计算能力,尤其是在拥有多个核心的处理器上。 ...
### Java多线程学习笔记 #### 一、线程的基本概念 在计算机科学中,**线程**(Thread)是程序执行流的最小单位。一个标准的程序只能做一件事情,而通过多线程技术,可以让程序同时处理多个任务。在Java中,线程是...
《良葛格 Java 学习笔记-JavaGossip全(v1+v2)》是一部集成了作者良葛格多年编程经验的学习资料,旨在帮助初学者和有经验的开发者深入理解和掌握Java这门强大的编程语言。这份笔记包含了JavaGossip的两个版本,v1和...
4. 多线程:在10多线程.md中,介绍了如何创建和管理Java线程,包括Thread类、Runnable接口,以及同步机制如synchronized关键字、wait()、notify()和notifyAll()方法。多线程技术是实现并发执行的关键,有助于提高...
除了synchronized,Java还提供了其他同步机制,如volatile变量,它能确保对变量的修改对所有线程都是可见的,但不保证原子性。另外,Java的并发包`java.util.concurrent`引入了显式锁(如`Lock`接口及其实现类),...
占式线程调度是Java和大多数现代操作系统采用的线程调度策略。在这种模式下,操作系统决定何时以及哪个线程将获得CPU的执行时间。线程的执行不是由线程自身控制,而是由操作系统通过时间片轮转或者优先级调度等方式...
Java线程是多任务编程的重要组成部分,它允许程序同时执行多个独立的代码片段,从而提高程序的效率和响应性。本文将深入探讨Java线程的概念、原理以及如何在实际编程中进行有效管理。 首先,我们要了解操作系统中的...
Java学习笔记是初学者探索Java编程世界的宝贵资源。这份由老师精心整理的课程笔记涵盖了Java的基础到进阶知识,旨在帮助新手快速理解并掌握这门强大的面向对象编程语言。笔记内容可能包括但不限于以下方面: 一、...
Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现为Oracle公司的一部分)于1995年发布。...Java学习笔记涵盖了这些核心知识点,通过深入学习和实践,你可以逐步掌握Java编程,并应用于实际项目开发中。
本笔记将深入探讨Java的基础知识和核心概念。 1. **Java基础** - **语法**:Java语法与C++类似,但更加简洁。例如,Java使用垃圾回收机制自动管理内存,避免了C++中的内存泄漏问题。 - **类与对象**:Java是面向...
在本压缩包“bjy学习笔记-阿里巴巴Java编码规范以及一些技术笔记”中,我们可以预见到包含的内容主要是关于Java编程语言的学习心得,特别是遵循阿里巴巴的Java编码规范的相关知识。这是一份宝贵的资源,对于Java...
Java 多线程是编程中的重要概念,尤其在并发处理和高效系统设计中扮演着关键角色。本节主要探讨了Java中的线程概念以及如何创建...通过不断的实践和学习,可以更好地利用Java的多线程特性来提升软件的性能和用户体验。
6. **多线程**:阐述Java中的并发编程,包括线程的创建、同步机制(synchronized、wait/notify、Lock接口)、线程池以及并发集合。 7. **设计模式**:介绍常见的设计模式,如单例、工厂、装饰器、观察者等,帮助...