具体知识学习与
https://blog.csdn.net/yansuoo/article/details/51248281
https://www.jianshu.com/p/6586d9f3b515
下面是自己的理解+代码:
一.前置知识:
java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的
二.代码理解
- synchronized(对象锁):两种;
-
synchronized(this){ //互斥代码 } 或: private Object lock = new Object(); public void test1(){ synchronized(lock){ //互斥代码 } }
这里的this,指的是调用它的实例对象,即锁就是这个这里对象 ; 而lock锁则是任意对象锁(所有需要这个对象的锁的方法都不能同时执行),有些许的不同(所有线程线程能共用该锁)。
-
代码:
Ticket t1=new Ticket(); Ticket t2=new Ticket(); Ticket t3=new Ticket(); t1.start(); t2.start(); t3.start(); //测试三个线程 class Ticket extends Thread{ private int num=100; //Object obj = new Object(); public void run() { while(true) { //synchronized (obj) synchronized (this) { if(num>0)System.out.println(Thread.currentThread().getName()+".."+num--); try { Thread.sleep(100); }catch (Exception e) {} } System.out.println(Thread.currentThread().getName()+":释放"); } } }
此时线程1.2.0.交替执行,但注意下一次线程1.2.0像执行必须对应锁释放,换句话说这里三个线程对象对应了三个锁,只锁自己,不能锁别人,cpu可以切换其他线程执行,只要没被锁。 而代码注释的第二种结果是: 与上面同理,也是只能锁自己。是把当前这个对象的成员变量(object)当做锁,其实三个线程对象有三个不同的object对象,因为这个变量不共享。
-
tips:这样加锁的好处 (这是最常用的高并发场景下要锁住某个方法所用的操作) :如果这时用synchronized来修饰代码块:synchronized(obj){obj.testsy();},那么这个方法加锁的对象是obj这个对象,跟执行这行代码的对象没有关系,当一个线程执行这个方法时,这对其他同步方法时没有影响的,因为他们持有的锁都完全不一样。
private Object lock = new Object(); public void test1(){ synchronized(lock){ //互斥代码 } }
-
private static Object lock = new Object();
但如果任意对象锁改为静态的,则可以实现互斥了,所有线程共享这个锁(共享这个变量)。
-
synchronized(类锁)
-
对于类锁来说其实和对象锁一样只是为了区别静态方法和普通方法,对于多个线程,都是一把锁,和第5点的情况一样
synchronized(A.class){ //互斥代码 }
tips:object.getClass()和A.class实际意义不同,并且对于前者来说,出现多态时,可能会有问题
-
每个线程执行都得等内阁唯一的一把锁释放。
三:一点解释:
Thread.sleep():强制线程休眠未来*ms时间内不进入CPU进行竞争,进入阻塞状态,给其他线程机会执行,但是,他不会释放锁;且 *毫秒过去之后,这时候也许另外一个线程正在使用CPU,那么这时候操作系统是不会重新分配CPU的, 直到那个线程挂起或结束;况且,即使这个时候恰巧轮到操作系统进行CPU 分配,那么当前线程也不一定就是总优先级最高的那个,CPU还是可能被其他线程抢占去。也不一定会论到调度他。
线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。