阅读前必须明白:
程序代码的目的是操作数据,而在操作数据时有可能发生同时操作同一个数据,所以为了避免同时操作一个数据产生错误才出现线程同步的概念,即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的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
【Java基础知识 第四节 多线程复习】中,同步代码块(synchronized关键字)的两个练习代码。
文章目录synchronized线程安全主要诱因互斥锁特性获取对象锁同对象,异步同对象,同步代码块同对象,非静态同步方法同对象,同步代码块 对比 非静态同步方法不同对象,同步代码块 对比 非静态同步方法获取类锁和对象...
一个简单的多线程代码示例,Java实现,用于实现同一时刻,只允许一个线程调用执行的代码块或类,即synchronized的如何使用(多线程实现),实现 Runnable
lock锁,lock锁和synchronized的对比 # Lock锁 JDK5.0后Java提供了一种更加强大的线程同步机制。一种显式定义同步锁对象来实现锁...Lock锁>同步代码块(已将进入了方法体,分配了相应的资源)>同步方法(在方法体外)
java多线程编程核心技术synchronized实例大全,同步方法,同步语句块,类锁,对象锁全都用代码来展现出来
多线程的学习的笔记 Thread1:继承Thread类 * Thread2:继承Runnable接口 * * ThreadMethod:一些Thread常见方法 * ThreadTestDome1 练习:创建两... * WindowTest1_safe1:安全的Thread--法1实现代码块synchronized
synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class ...
在Java中,synchronized关键字是用来控制线程同步的,是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。Synchronized既可以对代码块使用,也可以加在整个方法上。 关键是,不要认为给方法或者...
对于synchronized语句当Java源代码被javac编译成bytecode的时候,会在同步代码块的入口位置和退出位置分别插入monitorenter和monitorexit(2个)字节码指令。而synchronized方法则会被翻译成普通的方法调用和返回指令...
从尺寸上讲,同步代码块比同步方法小。你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间
原子性:被synchronized关键字包裹起来的方法或者代码块可以认为是原子的。因为在锁未释放之前,这段代码无法被其他线程访问到,所以从一个线程观察另外一个线程的时候,看到的都是一个个原子性的操作。在Java中,...
synchronized代码块,被修饰的代码成为同步语句块,其作用的范围是调用这个代码块的对象,我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。...
本文档主要讲述的是java synchronized详解;Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
它可以确保在同一时刻,只有一个线程能够访问被synchronized修饰的代码块或方法。这种机制可以有效地避免多线程环境下的数据竞争和不一致问题。 在Java中,锁膨胀(Lock Inversion)是一个重要的概念。当一个对象被多...
当线程进入synchronized修饰的方法或代码块时,会自动获取锁,并在退出时自动释放锁。而Lock接口则是一个更底层的同步机制,它提供了更丰富的功能,但需要显式地获取和释放锁,通常通过实现类如ReentrantLock来使用...