Android多线程-----同步锁

本文深入探讨了Java中的同步机制,包括synchronized关键字的使用方法及其作用于对象、函数及类的方式,ReentrantLock的高级特性如锁的获取与释放、公平性及Condition的使用等,以及Semaphore信号量的应用。
摘要由CSDN通过智能技术生成

一、同步机制关键字synchronized
对于java来说,最常用的同步机制就是synchronized关键字,他是一种基于语言的粗略锁,能够作用于对象、函数、class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的这个Class类,并非具体对象。

public class SynchronizedClass {
    public synchronized void syncMethod(){
        //代码
    }

    public void syncThis(){
        synchronized (this){
            //代码
        }
    }

    public void syncClassMethod(){
        synchronized (SynchronizedClass.class){
            //代码
        }
    }

    public synchronized static void syncStaticMethod(){
        //代码
    }
}

上面演示了同步方法、同步块、同步class对象、同步静态方法。前2种锁的是对象,而后两种锁的是class对象。对于class对象来说,它的作用是防止多个线程同时访问添加了synchronized锁的代码块,而synchronized作用于引用对象是防止其他线程访问同一个对象中synchronized代码块或者函数。

二、显示锁———-ReentrankLock和Condition
ReentrankLock 和内置锁synchronized相比,实现了相同的语义,但是更具有更高的灵活性。
(1)获得和释放的灵活性。
(2)轮训锁和定时锁。
(3)公平性。
基本操作:
lock(): 获取锁

tryLock(): 尝试获取锁

tryLock(long timeout,TimeUnit unit): 尝试获取锁,如果到了指定的时间还获取不到,那么超时。

unlock(): 释放锁

newCondition(): 获取锁的 Condition

使用ReentrantLock的一般组合是 lock、tryLock、与unLock成对出现,需要注意的是,千万不要忘记调用unlock来释放锁,负责可能引发死锁的问题。ReentrantLock的常用形式如下所示:

public class ReentrantLockDemo {
    Lock lock = new ReentrantLock();

    public void doSth(){
        lock.lock();
        try {
            //执行某些操作
        }finally {
            lock.unlock();
        }
    }
}

需要注意的是,lock必须在finally开中释放,否则,如果受保护的代码抛出异常,锁就可能永远得不到释放!!

ReentrantLock类中还有一个重要的函数newCondition(),该函数用户获取Lock()上的一个条件,也就是说Condition与Lock绑定。Condition用于实现线程间的通信,他是为了解决Object.wait(),nofity(),nofityAll() 难以使用的问题。
Condition的方法如下:

await() : 线程等待

await(int time,TimeUnit unit) 线程等待特定的时间,超过的时间则为超时。

signal() 随机唤醒某个等待线程

signal() 唤醒所有等待中的线程

示例代码:

public class MyArrayBlockingQueue<T> {

//    数据数组
    private final T[] items;

    private final Lock lock = new ReentrantLock();

    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition() ;

//    头部索引
    private int head;
//    尾部索引
    private int tail ;
//    数据的个数
    private int count;

    public MyArrayBlockingQueue(int maxSize) {
        items = (T[]) new Object[maxSize];
    }

    public MyArrayBlockingQueue(){
        this(10);
    }

    public void put(T t){
        lock.lock();
        try {
            while(count == getCapacity()){
                System.out.println("数据已满,等待");
                notFull.await();
            }
            items[tail] =t ;
            if(++tail ==getCapacity()){
                tail = 0;
            }
            ++count;
            notEmpty.signalAll();//唤醒等待数据的线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public int getCapacity(){
        return items.length ;
    }

    public T take(){
        lock.lock();
        try {
            while(count ==0){
                System.out.println("还没有数据,等待");
                //哪个线程调用await()则阻塞哪个线程
                notEmpty.await();
            }
            T ret = items[head];
            items[head] = null ;
            if(++head == getCapacity()){
                head =0 ;
            }
            --count;
            notFull.signalAll();
            return ret ;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return null ;
    }

    public int size(){
        lock.lock();
        try {
            return  count;
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args){
        MyArrayBlockingQueue<Integer> aQueue = new MyArrayBlockingQueue<>();
        aQueue.put(3);
        aQueue.put(24);
        for(int i=0;i<5;i++){
            System.out.println(aQueue.take());
        }

        System.out.println("结束");
    }
}
执行结果:
3
24
还没有数据,等待

三、信号量 Semaphore

Semaphore是一个计数信号量,它的本质是一个“共享锁”。信号量维护了一个信号量许可集,线程可以通过调用acquire()来获取信号量的许可。当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到可用的许可为止。线程可以通过release()来释放它所持有的信号量许可。
示例:

public class SemaphoreTest {
    public static void main(String[] args){
        final ExecutorService executorService = Executors.newFixedThreadPool(3);
        final Semaphore semaphore = new Semaphore(3);
        List<Future> futures = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Future<?> submit = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println(" 剩余许可: " + semaphore.availablePermits());
                        Thread.sleep(3000);
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            futures.add(submit);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值