`

[#0x004C] Java多线程:synchronized

    博客分类:
  • Java
阅读更多

  首先明确一点,同步方法本质上也是一个同步控制块(仅针对于锁定this的情况,如果同步控制块锁定的不是this,那么它是不能直接改写为同步方法的),区别在于同步方法的粒度是整个方法,而同步控制块的粒度可以是方法的一部分。

// 同步方法示例
public class Counter {
	int count;
	static int classCount;
	
	public synchronized void bump() {
		System.out.println("bump() starts");
		count++;
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("bump() ends");
	}
	
	public static synchronized void classBump() {
		classCount++;
		System.out.println("classBump()");
	}
}

// 同步方法可以等价地写成同步控制块
public class Counter {
	int count;
	static int classCount;
	
	public void bump() {
		synchronized (this) {
			// ...
		}
	}
	
	public static void classBump() {
		synchronized (Counter.class) {
			// ...
		}
		
		// 或者不用Counter.class,用Class.forName()
		/**
		try {
			synchronized (Class.forName("Counter")) {
				// ...
			}
		} catch (ClassNotFoundException e) {
			e.printStack();
		}
		*/
	}
}

 

  从这个例子可以看出,Class锁(针对static方法)和Object锁(针对非static方法)是两种锁。从实验的结果来看,这两种锁是不冲突的,即:假设有Counter c = new Counter();,如果Thread A调用c.bump()方法,那么synchronized(this)只是锁定了c这个对象,Thread B可以无所顾忌地调用Counter.classBump()(或者c.classBump()也可以),不用等待Thread A释放c的锁。如:

public class MultiThreadTest8 {
	public static void main(String[] args) {
		final Counter c = new Counter();
		
		Thread t1 = new Thread(
				new Runnable() {
					@Override public void run() {
						c.bump();
					}
				}, "Runner 1");
		
		Thread t2 = new Thread(
				new Runnable() {
					@Override public void run() {
						//Counter.classBump();
						c.classBump();
					}
				}, "Runner 2");
		
		t1.setPriority(Thread.NORM_PRIORITY + 2);
		t1.start();
		t2.start();
		
		// output: 
		/**
			bump() starts
			classBump()
			bump() ends		
		*/
	}
}

 

  不过一旦Thread A调用c.bump(),锁定了c,那么Thread B就不能调用c.bump()了,c中的其他同步方法或是同步控制块Thread B也不能访问,只有等到Thread A释放c的锁(即c.bump()同步部分执行完)。Counter的非同步方法不受锁的限制,即使Thread A锁定了c,Thread B也可以随意访问c的非同步方法。

 

p.s. 这里说锁定一个对象,并不是说属性不能访问,锁定对象只是锁定同步方法或是同步控制块,使同步方法或是同步控制块的执行不会被其他线程打断(可以理解为:锁定方法到一个线程)。如果有一个同步方法去修改某个字段,此时是可以有另一个非同步方法也去修改这个字段,这样仍然有可能产生数据不一致的情况。

 

p.s. synchronized关键字可以放在类的前面,表示类中的所有方法都是同步方法。

分享到:
评论

相关推荐

    Java多线程和JUC.pdf

    ### Java多线程和JUC知识点详解 #### Lambda表达式与函数式编程 Lambda表达式是Java 8引入的一个重要特性,它支持将函数作为参数传递到方法中,极大地简化了代码编写。Lambda表达式的使用使得Java语言更加简洁、易...

    【多线程与高并发原理篇:4_深入理解synchronized】.doc

    在Java多线程编程中,`synchronized`关键字是实现线程安全的关键工具之一,它提供了一种同步机制,确保共享资源在同一时间只能被一个线程访问。本文将从应用层、字节码层面和Java虚拟机规范层面三个方面深入探讨`...

    Java多线程面试题

    Java多线程面试题是Java程序员面试中常见的部分,尤其在金融行业的电子交易系统开发中,对并发处理能力的要求非常高。以下是对这些面试题的详细解答: 1) 保证线程顺序执行:可以通过调用`Thread.join()`方法实现。...

    JStack和Java Thread Dumps分析

    这对于诊断线程挂起、死锁和其他多线程问题非常有用。 #### 三、JStack的使用 ##### 1. 基本用法 要使用`JStack`,首先需要确定目标Java进程的PID(进程ID)。可以通过`jps`命令获取: ```bash jps -l ``` 该...

    详解Java线程堆栈

    Java线程堆栈是一种强大的诊断工具,能够帮助开发者快速定位多线程应用程序中的问题。通过分析线程堆栈,可以找到系统中各种问题的根源,如系统无缘无故CPU过高、系统挂起、系统运行越来越慢、性能瓶颈、线程死锁、...

    Java线程Dump分析工具jstack解析及使用场景

    `"waiting to lock <0x00000000acf4d0c0>"`表明线程在尝试获得特定内存地址的锁。通过在dump文件中搜索该内存地址,可以找到持有该锁的线程,从而帮助定位问题。 实例二展示了`WAITING on condition`和`TIMED_...

    java串口操作源码

    9. **同步机制**:在多线程环境下,需要使用同步机制(如`synchronized`关键字或`ReentrantLock`)来保证对串口资源的安全访问。 10. **监听器和事件驱动**:可以设置串口监听器来响应接收到的数据,采用事件驱动的...

    java问题定位技术+性能优化

    - 并发优化: 合理利用多线程,减少线程间竞争。 - **2.2.4 性能调优的终结条件** - 达到预定的性能指标。 - 确保系统的稳定性和可维护性不受影响。 - **2.2.5 性能调优工具** - VisualVM: 提供了线程分析、内存...

    JAVA基础教程

    - **多线程**:Java支持多线程编程,可以同时执行多个任务,提高了程序的并发性和响应速度。 - **高性能**:虽然Java是一种解释型语言,但通过JIT编译器等技术实现了接近于本地代码的性能。 #### 二、Java编程基础 ...

    Java基础整理

    - **多线程创建**:可以通过继承`Thread`类或实现`Runnable`接口来创建线程。 - **常用方法**:`start()`启动线程,`run()`定义线程体,`join()`等待线程结束。 - **线程状态**:线程在其生命周期中会经历不同的状态...

    福富2010 Java 面试题

    * Java中提供了多种同步机制,例如:`synchronized`关键字、`Lock`接口等 对象的定义 * 对象是指Java中的一个实例,例如:`Object obj = new Object();` * 对象可以具有多种类型,例如:`String`、`Integer`等 ...

    java学习初级课件mht格式

    7. **多线程编程**:介绍如何创建和管理线程,包括同步机制(如synchronized关键字、wait/notify机制)和并发工具类(如ExecutorService、Semaphore)。 8. **Java Swing和JavaFX**:对于GUI(图形用户界面)编程,...

    Java精选笔试题考卷(附完整答案).docx

    `java.util.Hashtable`是线程安全的容器类,而`synchronized`关键字可以用来同步代码块或方法,保证在多线程环境中的数据一致性。 3. **CMS垃圾回收算法的缺点** - **选项ABC**指出了CMS垃圾回收器的主要缺点。...

    java软件技术文档-深入java8的集合5:Hashtable的实现原理.pdf

    与HashMap不同,Hashtable保证了线程安全,所有公共方法都使用`synchronized`关键字进行了同步,确保在多线程环境下也能正确工作。然而,这种同步机制也带来了性能上的牺牲,因为在单线程环境中,Hashtable的效率...

    JAVA 语言程序设计考试试卷.docx

    根据提供的文件信息,我们可以归纳出一系列与Java编程相关的知识点,主要围绕题目中涉及的基础概念、语法结构、数据类型以及程序设计原则等。 ### 单选题解析 #### 1. 下列语句序列执行后,k的值是() 题目描述不...

    java编码规范.pdf

    - **目的**:确保程序在多线程环境下的正确执行。 **5.4 控制语句** - **规则**:合理使用循环、条件判断等控制语句。 - **目的**:编写逻辑清晰、高效的代码。 **5.5 注释规约** - **规则**:在必要时添加注释,...

    JAVA SE概要点总结

    - **多线程**:Thread类和Runnable接口用于实现多线程,synchronized关键字保证线程安全。 - **集合框架**:ArrayList、LinkedList、HashSet、HashMap等,以及它们的遍历和操作方法。 以上是JAVA SE的一些核心...

    2021-2022计算机二级等级考试试题及答案No.420.docx

    5. **同步机制**:Java语言支持线程间的同步操作,以确保多线程环境下的数据安全。同步方法可以通过在方法定义时加上`synchronized`关键字来实现。同步方法的锁对象是方法所属的对象,即通过`this`关键字引用当前...

    JAVA SE概要点总结

    Java通过`Thread`类支持多线程编程,`synchronized`关键字用于线程同步,`wait()`和`notify()`用于线程通信。`Runnable`接口是另一种实现多线程的方式。 **14. 核心类库** Java提供了丰富的核心类库,如集合框架...

Global site tag (gtag.js) - Google Analytics