阅读前必须明白:
程序代码的目的是操作数据,而在操作数据时有可能发生同时操作同一个数据,所以为了避免同时操作一个数据产生错误才出现线程同步的概念,即synchronized方法和synchronized代码块技术。
这里的同一个数据包括 所有对象...
还有每一个对象都有一把锁,synchronized就是为此对象上锁,等到synchronized方法或synchronized代码块执行完就会自动解锁,所有多线程执行相同带synchronized的代码时会检查所操作对象是否上锁,如果已经被锁住,就阻塞等待,直到锁此代码段的线程执行完此代码块。
所以非synchronized方法不会有阻塞一说,因为它没有synchronized,所以不会检查对象锁住没有
若想深入了解对象锁机制,参考http://zhangjunhd.blog.51cto.com/113473/70300
synchronized方法和synchronized代码块的理解:
synchronized方法锁住的是this,
synchronized(this){ },锁住this,只要多个线程同时访问同一个SynchronizedTest实例(this),就会发生不能同时访问此代码块
synchronized(Object){ },锁住Object,只要多个线程同时访问同一个Object就会发生不能同时访问此代码块
同步的目的就避免操作同一个数据,所以操作不同数据就不必要同步。
理解下面代码的区别,就真正理解了同步:
public class SynchronizedTest{ Person p = new Person("lin", 15); public synchronized void say(){//相当于锁住this,效果和say3()一样,只要多个线程同时访问同一个SynchronizedTest实例(相当于this),就会发生不能同时访问此方法 System.out.println(p.getName()); } public void say2(){ synchronized(p){//相当于锁住p,只要多个线程同时访问此代码块且是同一个p,就会发生不能同时访问此代码块锁住 System.out.println(p.getName()); } } public void say3(){ synchronized(this){//锁住this,效果和say()一样,只要多个线程同时访问同一个SynchronizedTest实例(this),就会发生不能同时访问此代码块 System.out.println(p.getName()); } } }
明白则一点,就阅读下面:
我就偷点懒,摘抄一下别人的,其实人家和我要写的差不多
以下摘自http://blog.csdn.net/xiao__gui/article/details/8188833
在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。Synchronized既可以对代码块使用,也可以加在整个方法上。
关键是,不要认为给方法或者代码段加上synchronized就万事大吉,看下面一段代码:
- class Sync {
- public synchronized void test() {
- System.out.println("test开始..");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("test结束..");
- }
- }
- class MyThread extends Thread {
- public void run() {
- Sync sync = new Sync();
- sync.test();
- }
- }
- public class Main {
- public static void main(String[] args) {
- for (int i = 0; i < 3; i++) {
- Thread thread = new MyThread();
- thread.start();
- }
- }
- }
运行结果:
test开始..
test开始..
test开始..
test结束..
test结束..
test结束..
可以看出来,上面的程序起了三个线程,同时运行test方法,虽然test方法加上了synchronized,但是还是同时运行起来,貌似synchronized没起作用。
将test方法改成如下:
- public void test() {
- synchronized(this){
- System.out.println("test开始..");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("test结束..");
- }
- }
运行结果:
test开始..
test开始..
test开始..
test结束..
test结束..
test结束..
一切还是这么平静,没有看到synchronized起到一丝作用。
实际上,synchronized(this)以及非static的synchronized方法(至于static synchronized方法请往下看),只能防止多个线程同时执行同一个对象的这个代码段。
为什么会这样呢,回到本文的题目上:Java线程同步:synchronized锁住的是代码还是对象。答案是:synchronized锁住的是括号里的对象,而不是代码。对于非静态的synchronized方法,锁的就是对象本身也就是this。
当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。
所以我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。原因是基于以上的思想,锁的代码段太长了,别的线程是不是要等很久,等的花儿都谢了。当然这段是题外话,与本文核心思想并无太大关联。
再看上面的代码,每个线程中都new了一个Sync类的对象,也就是产生了三个Sync对象,由于不是同一个对象,所以可以多线程同时运行synchronized方法或代码段。
为了验证上述的观点,修改一下代码,让三个线程使用同一个Sync的对象。
- class MyThread extends Thread {
- private Sync sync;
- public MyThread(Sync sync) {
- this.sync = sync;
- }
- public void run() {
- sync.test();
- }
- }
- public class Main {
- public static void main(String[] args) {
- Sync sync = new Sync();
- for (int i = 0; i < 3; i++) {
- Thread thread = new MyThread(sync);
- thread.start();
- }
- }
- }
运行结果:
test开始..
test结束..
test开始..
test结束..
test开始..
test结束..
可以看到,此时的synchronized方法和synchronized代码段就都起了作用。
那么,如果真的想锁住这段代码,要怎么做?也就是,如果还是最开始的那段代码,每个线程new一个Sync对象,怎么才能让test方法不会被多线程执行。
解决也很简单,只要锁住同一个对象不就行了。例如,synchronized后的括号中锁一个static final对象,这样就行了。这样是没问题,但是,比较多的做法是让synchronized锁这个类对应的Class对象。
- class Sync {
- public void test() {
- synchronized (Sync.class) {
- System.out.println("test开始..");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("test结束..");
- }
- }
- }
- class MyThread extends Thread {
- public void run() {
- Sync sync = new Sync();
- sync.test();
- }
- }
- public class Main {
- public static void main(String[] args) {
- for (int i = 0; i < 3; i++) {
- Thread thread = new MyThread();
- thread.start();
- }
- }
- }
运行结果:
test开始..
test结束..
test开始..
test结束..
test开始..
test结束..
上面代码用synchronized(Sync.class)实现了全局锁的效果。
最后说说static synchronized,实际上static方法可以直接类名加方法名调用,方法里面没有this这个概念,所以,static synchronized方法也相当于全局锁,相当于锁住了代码段。
相关推荐
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
本教程将深入讲解Java中的多线程以及同步控制机制,特别是同步代码块和同步方法。 首先,我们要理解什么是线程。线程是程序执行的最小单位,一个进程中可以有多个线程并发执行。在Java中,可以通过实现`Runnable`...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
synchronized 关键字可以应用在方法和代码块中,以实现互斥同步原语。通过 synchronized 关键字,我们可以对对象锁和类锁进行操作,从而实现线程安全。 synchronized 关键字的原理 synchronized 关键字的原理是...
此外,Java还提供了其他同步机制,例如`synchronized`关键字,可以用来锁定代码块或整个方法,确保同一时间只有一个线程能执行特定代码。另外,`wait()`和`notify()`方法可以用于线程之间的通信,但它们必须在`...
总结来说,Java中的同步代码块是一种有效的解决线程安全问题的手段,通过限制对共享资源的并发访问,可以保证数据的一致性和线程的安全性。然而,过度使用同步可能会降低程序的性能,因此需要合理设计同步范围,确保...
当一个线程进入同步代码块时,其他试图进入相同同步代码块的线程会被阻塞,直到该线程完成其执行并释放锁。 同步块通常使用`synchronized`关键字来实现。它的基本语法结构如下: ```java synchronized(对象引用) {...
Java 线程同步机制中 synchronized 关键字的理解 ...它可以作用于对象、类和方法,实现多个线程的同步访问。然而,需要注意 synchronized 方法的缺陷,并且尽量避免无谓的同步掌握,以免对系统性能产生影响。
在这个例子中,`increment()`和`decrement()`方法都用到了同步代码块,使得计数操作不会因线程并发而出现不正确的结果。 通过这两个示例,我们可以学习到同步代码块在实际编程中的应用,以及如何解决多线程环境下的...
- **同步锁的选择**:使用了一个名为`threadCounterLock`的静态变量作为锁对象,确保每次只有一个线程能进入`synchronized`代码块。 - **循环和休眠处理**:在`run`方法中,线程会持续运行直到达到预设的时间点(30...
- **同步代码块**:通过synchronized关键字定义的代码块,可以确保一次只有一个线程可以执行该代码块中的代码。同步代码块通常需要指定一个锁对象,这个对象用于控制对共享资源的访问。 - **同步方法**:同步方法是...
它可以用于方法或代码块,确保同一时间只有一个线程能执行特定代码,从而实现线程间的互斥访问。 2. **volatile** 关键字:`volatile`保证了变量在所有线程中的可见性,但不保证原子性。如果一个变量被多个线程共享...
当一个线程进入synchronized代码块或方法时,它会获取与该代码块或方法关联的对象锁。其他尝试进入相同代码块或方法的线程将被阻塞,直到当前线程执行完毕并释放锁。这样可以确保在任何给定时刻,只有一个线程能够...
总结起来,`@synchronized`是一种便捷的多线程同步手段,通过递归互斥锁实现代码的原子性。在使用时应注意以下几点: 1. `@synchronized`是基于对象的,传入的对象不能为`nil`,否则无效。 2. 由于使用了递归锁,它...
在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用synchronized关键字还不能满足对多线程进行同步的所有需要。因此,需要使用其他同步机制来满足不同的同步需求。 Java 多线程同步中的...
本篇文章将详细介绍`synchronized`的两种形式:同步代码块和同步方法,并分析它们的区别。 1. **同步代码块 (Synchronized Block)** 同步代码块的语法结构如下: ```java synchronized (object) { // 需要同步...