前言:
谈到多线程,就不得不说线程同步,那么什么是线程同步?
线程同步
即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,简单来说,就是一个线程在对内存进行操作,如修改一个对象,其他线程不能对该对象进行修改,等该线程执行完毕后,才能进行操作。实现线程同步的方法有很多,java中常用synchronized锁来实现。
下面用一个小demo来说明一下区别
-火车站有三个窗口进行售票,总共有100张票,窗口名分别:为窗口A,窗口B,窗口C
-每售出一张票耗时100毫秒,售出后打印出由哪个窗口售出且还剩多少张票.
运行结果
从结果可以看出,3个窗口卖多了一张票,这就是线程不同步出现的问题,从上面可以看出当还剩一张票时,ABC三个线程都拿到了这张票,然后都分别卖出去了,导致--操作发生了多次产生了负数,这在实际生活中显然 是不允许的,那么如何去解决?
synchronized锁可以将该操作锁起来,就比如你去卫生间,把门一关,别人就进不来了,只能等你把事情做完了,他才能进去。那么如何去实现?
只需在卖票的代码块上加上一个锁即可,注意的是多个线程拿到的锁对象必须相同,在这里我们直接使用了TicketsSeller.class,这个MyThread.class是一个全局唯一的,我们同样可以自定义一个静态变量来当作锁对象,只要保证多个线程拿到的是同一个对象即可。
要注意的是锁对象范围越大,性能越低,本次demo使用的串行效率也比较比,在实际开发中,如果不是严格要求一般不会用到
当然锁并不是只有这一种,分很多种,下面简单介绍下锁的分类。具体的需要大家在实际开发中取接触,了解。
偏向锁、自旋锁、重量级锁
Java在使用synchronize关键字,首先在Java对象头进行markword,记录这个线程id,只有一个线程对这个对象加锁,这个锁叫做偏向锁。
偏向锁如果有线程争用,那么升级为自旋锁?一个锁如果被使用,那么另外一个线程打算争抢这把锁,则会陷入while循环,形成自旋。这叫做自旋锁。
旋10次之后,升级为重量级锁。重量级锁以OS为主体。那么重量级锁不会占用CPU。
注:锁不能降级
公平锁、非公平锁
公平锁:加锁之前先检查是否有排队等待的线程,有的话优先处理排前面的线程,先来先得。
非公平锁:线程加锁时直接尝试获取,获取不到就到队尾等待
非公平锁 Lock nonFairLock=new ReentrantLock(true);//默认空参是true
公平锁 Lock fairLock=new ReentrantLock(false);
注:非公平锁比公平锁快很多
7.3.重入锁
ReetranLock含义是重入锁,什么意思呢,可以进行加锁多次,和解锁多次,比如