Java高并发编程:线程锁技术

来源:互联网 发布:ubuntu更新命令 编辑:程序博客网 时间:2024/05/22 03:19

一、Lock

1.synchronized : 传统线程模型。


2.Lock : 同步锁接口

Lock lock = new ReentrantLock();//获取锁实例对象


3.ReentrantLock:lock()unlock()newCondition()


Lock lock = new ReentrantLock();//获取锁实例对象

lock.lock();

lock.unlock();


4.ReadWriteLock : 读写锁接口

ReadWriteLock rwl = new ReentrantReadWriteLock();//定义读写锁


5.ReentrantReadWriteLock : readLock()获取读锁,writeLock()获取写锁

ReadWriteLock rwl = new ReentrantReadWriteLock();//定义读写锁

rwl.readLock().lock(); // 上读锁

rwl.readLock().unlock();// 释放读锁

rwl.writeLock().lock(); // 上写锁

rwl.writeLock().unlock();// 释放写锁


//实例:读写锁的基本用法,读写锁用于缓存数据

public class ReadWriteLockTest {

    

    public staticvoid main(String[] args) {

        final Queue3 q3 = new Queue3(); //封装共享的数据、读写锁和待执行的任务的类

        

        for (int i =0; i < 3; i++) {

            new Thread() { // 开启三个线程写数据

                public void run() {

                    while (true) {

                        q3.put(new Random().nextInt(10000));

                    }

                }

            }.start();

            

            new Thread() { // 开启三个线程读数据

                public void run() {

                    while (true) {

                        q3.get();

                    }

                }

            }.start();

        }

    }

}


class Queue3 {

    

    private Object data = null; //共享的数据

    private ReadWriteLock rwl = new ReentrantReadWriteLock();//定义读写锁

    

    // 读取数据的任务方法

    public void get() {

        rwl.readLock().lock(); //上读锁

        try {

            System.out.println(Thread.currentThread().getName()

                               + ":before read: " + data);// 读之前打印数据显示

            

            Thread.sleep((long) (Math.random() *1000)); //睡一会儿~

            

            System.out.println(Thread.currentThread().getName()

                               + ":after read: " + data);// 读之后打印数据显示

        } catch (InterruptedException e) {

            e.printStackTrace();

        } finally {

            rwl.readLock().unlock();//释放读锁

        }

    }

    

    // 写数据的任务方法

    public void put(Object data) {

        rwl.writeLock().lock(); //上写锁

        try {

            System.out.println(Thread.currentThread().getName()

                               + ":before write: " + this.data);// 读之前打印数据显示

            

            Thread.sleep((long) (Math.random() *1000)); //睡一会儿~

            this.data = data; //写数据

            

            System.out.println(Thread.currentThread().getName()

                               + ":after write: " + this.data);// 读之后打印数据显示

        } catch (InterruptedException e) {

            e.printStackTrace();

        } finally {

            rwl.writeLock().unlock();//释放写锁        

        }

    }

}


二、Condition

Condition的执行方式,是当在线程1中调用await方法后,线程1将释放锁,并且将自己沉睡,等待唤醒,

线程2获取到锁后,开始做事,完毕后,调用Conditionsignal方法,唤醒线程1,线程1恢复执行。


1.await(): 线程等待

2.await(long time, TimeUnit unit):线程等待特定的时间,超过等待时间则为超时

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

4.signalAll() : 唤醒所有等待中的线程


应用:阻塞队列


//实例

class BoundedBuffer {

    

    final Lock lock = new ReentrantLock();

    final Condition notFull  = lock.newCondition();

    final Condition notEmpty = lock.newCondition();

    

    final Object[] items = new Object[100];

    int putptr, takeptr, count;

    

    public void put(Object x) throws InterruptedException {

        lock.lock();

        try {

            while (count == items.length)//循环判断队列是否已存满

                notFull.await();    //如果队列存满了,则要存入数据的线程等待

            items[putptr] = x;

            if (++putptr == items.length) putptr =0;//当队列放满,指针回到0

            ++count;      //添加了一个数据

            notEmpty.signal();    //队列中有数据了,所以就唤醒取数据的线程

        } finally {

            lock.unlock();

        }

    }

    

    public Object take() throws InterruptedException {

        lock.lock();

        try {

            while (count ==0)    //循环判断,队列是否有空位

                notEmpty.await();   //要取的线程等待

            Object x = items[takeptr];

            if (++takeptr == items.length) takeptr =0;

            --count;  //取走一个,说明队列有空闲的位置,

            notFull.signal(); //所以通知存入的线程  

            return x;  

        } finally {  

            lock.unlock();  

        }  

    }   

}


原创粉丝点击