同步锁
我们在学习的时候,要带着一个疑问,就是同步锁是干什么的,同步锁呢,有三种类型的锁,一种是lock锁,一种是synchronize锁,还有一种呢是vilatile锁,这是三种锁的模式,我们接下来来看一下这三种锁都有什么区别,怎么使用。
*多线程操作的时候为什么会出现安全问题
*因为一个线程在进行运算的时候,另外一个线程也参与了运算
*用法:synchronize(唯一锁){要锁的代码块}
*synchronize(唯一锁),括号里面有三种写法
*一种是创建一个Object对象,用对象锁,
*第二种是括号里面写this
*第三种是括号里面写这个类的类名.class
*/
public class TickedThread {
public static void main(String[] args) {
Ticket ticket=new Ticket();
Thread thread = new Thread(ticket,"售票员小张");
thread.start();
Thread thread1 = new Thread(ticket,"售票员小刘");
thread1.start();
}
}
class Ticket implements Runnable{
//总票数
private int ticketCount=200;
@Override
public void run() {
//假设小张先来查票,现在是最后一张票 tikectCount=1
//小张被领导叫走后小刘也过来查票,此时的ticketCount=1
while(true) {
//加了一个同步锁,两个线程是同步的,就不会出现重读的问题了
//线程每进入循环一次,就判断前面的线程有没有开锁
synchronized(Ticket.class) {
if(ticketCount>0) {
try {
//小张在出票的时候被领导叫走了
//这个时候呢,小刘也要卖这张票
//线程睡眠是在模拟网络延迟的情况
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在售票,剩余"+(--ticketCount));
}
}
}
}
这个锁呢,是我们平时写程序开多个线程的时候用的最多的锁
synchronized锁:
synchronized修饰静态方法,代表的锁的是这个类对象.
synchronized修饰普通方法,代表锁的是当前实例对象;
其实这三种锁都能保证我们的数据同步,不会出现重复数据的问题。
lock锁
public static void main(String[] args) {
//创建锁对象
Lock lock=new ReentrantLock();
//创建要执行的任务
Ticket ticket=new Ticket(lock);
//创建线程并开启线程
Thread t1=new Thread(ticket,"售票员张小飞");
t1.start();
Thread t2=new Thread(ticket,"售票员关小羽");
t2.start();
}
}
class Ticket implements Runnable{
private Lock lock;
private int count=300;
public Ticket(Lock lock) {
this.lock=lock;
}
@Override
public void run() {
while(true) {
//使用lock锁进行加锁
lock.lock();
if(count>0) {
try {
Thread.sleep(50);
System.out.println(Thread.currentThread().getName()+"售出一张票,剩余"+(--count)+"张");
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
synchronized锁和lock锁的区别:两者都是可重入锁,自己可以再次获取自己的内部锁,就是说获取锁之后,可能还要获取,可能就会再次获取到
synchronized锁和lock锁的区别:synchronized是依赖于虚拟机的,哪怕只有一个虚拟机,也能识别synchronized,而Lock锁依赖于API(jdk)
synchronized锁和lock锁的区别:synchronized锁可以自动释放锁,而Lock锁必须要手动释放锁
synchronized锁和lock锁的区别:synchronized锁的两个线程1和线程2,如果当前线程1获得锁,线程2等待,如果线程1阻塞,线程2会一致等待下去, 而Lock锁不一定会等下去,如果尝试获几次取不到锁,线程2可以不用一直等待就结束了。
vilatile锁
这个锁呢,我们不常用,但是还是要知道他和其他锁的区别:
volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。
多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞
volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。
volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性