javad多线程的显示锁和内置锁

一、内置锁:Synchronized
1、内置锁的获得锁和释放锁是隐式的,进入synchrnozied修饰的代码要获得锁,走出相应的代码要释放锁。

2、与synchronized配套使用的线程通信方式:wait() 、notify() 、notifyAll()
wait会立刻释放当前锁,并进入等待状态,等待的到相应的notify重新获得锁后才继续执行。
notify不会立刻释放锁,而是等到notify所在synchronized代码块全部都执行完以后才会释放锁。
notifyAll会通知等待队列中的所有线程。

3、内置锁,在进入同步代码块时,采取的时无限等待的策略,一旦开始等待,就既不能中断也不能取消,容易产生饥饿和死锁问题。

二、显示锁:ReentrantLock
1、需要显示进行lock和unlock操作
2、RenntrantLock实现了Lock接口,并提供了与Synchronized相同的互斥性和内存可见性。
Lock lock=new ReentrantLock();
上锁: lock.lock();
释放锁:lock.unlock(); (最好放在finally块中,确保能执行)

3、同步锁Lock也有对应的线程通信机制:Condition
Condition c=lock.newCondition();
等待: c.await()
唤醒:c.signal() 和 c.signalAll()

注意:无论是内置锁还是显示锁,创建多个线程时都应该确保所使用的锁对象都应该是同一个。

注意:为了避免 虚假唤醒 的问题,wait应该尽可能放在while循环判断中

   public static void main(String[] args){
       
            Ticket t=new Ticket();     //只创建一个对象,确保三个线程所使用的是同一把锁
            new Thread(t,"一号窗口").start();
            new Thread(t,"二号窗口").start();
            new Thread(t,"三号窗口").start();
    }
    class Ticket implements Runnable{
        Lock lock=new ReentrantLock();
        public  int tickets=100;
        public void run(){
            while(true){
                try {
                    Thread.sleep(100);
                    lock.lock();    //上锁
                    if (tickets > 0)
                        System.out.println(Thread.currentThread().getName() + "完成售票,剩余票数:" + --tickets);
                    else
                        return;
                }catch(Exception e){
    
                }
                finally {
                    lock.unlock();   //放在finally中,确保执行完时会释放锁
                }
            }
        }
    
    }

猜你喜欢

转载自blog.csdn.net/Owen_L_Y/article/details/84781123