多线程基础讲解十: 多线程的Lock锁,多线程同步、多线程并发的概念

同步 和 并发 : 对于程序员来说,他们其实是有两个意思的,一个是多线程层面,一个是网站请求服务器层面。

对于网站的请求层面来说:

同步:就是代码一步一步的有顺序的向下执行。

并发:就是多个请求同时访问一台服务器。

对于多线程层面来说:

同步: 就是加锁,为了保证数据的原子性。也就是保证数据的正确性。

并发:就是多个线程,操作同一个共享的资源。

所以:他们之前是有区别的,不是一个概念。

那么线程同步提高了效率吗 ?

没,降低了程序效率,因为程序中有阻塞,最主要的是抢锁耗费了很多资源,所以效率并不高。

接下来就说说Lock锁,他是jdk1.5提供并发包的一个工具。以前没有Lock锁的时候,大家都是用synchronized做锁。那为什么用Lock做锁呢 ?换句话说:就是Lock锁与synchronized的区别是什么 ?

用过synchronized的人都知道,synchronized(){} 这后面的{}就是需要被锁住的代码。他这个是自动的将包裹的代码全部上锁,执行到最后一个花括号就自动解锁。

而Lock锁,是手动上锁,手动解锁,相对来说更加灵活。而且效率也比synchronized的效率高,jdk1.5专门为多线程开发工具包,处理了很多效率问题,所以推荐使用。

区别:

1. Lock锁,可以尝试非阻塞式的获取锁,当线程获取到锁之后,就会持有锁,只要程序没有手动的释放锁,那么这个锁是绝对不会被释放的。还可以在任意位置,手动的释放锁。还可以指定时间范围内获取到锁,如果指定时间范围内,依然没有获取到锁,则返回,重新开始。所以Lock锁是相当灵活的。

2. synchronized是属于代码块,当代码执行完毕之后,或者中间出现异常,就会自动的释放锁资源,功能比较单一,且效率没有Lock锁高。

接下来,就用一下Lock做锁,并实现一下在使用Lock锁的情况下,怎么来完成线程之前的通讯。  

public class Person {

    public String username;
    public int age;

    /**
     * true 生产者线程等待,   false 消费者线程等待
     */
    public boolean flag = false;

    /**
     * 重入锁
     */
    public Lock lock = new ReentrantLock();
}






public class WriteThread extends Thread {

    private Person person;
    public Condition condition;

    public WriteThread(Person person, Condition condition) {
        this.person = person;
        this.condition = condition;
    }

    @Override
    public void run() {

        /**
         * 定义一个局部变量。
         * 当这个值为偶数时,为Person类赋值: 偶数   0
         * 当这个数为奇数时,为Person类赋值: 奇数   1
         */
        int data = 0;

        while (true) {

            try {
                //开启锁,注意这个锁的位置,一定要在上面。
                person.lock.lock();

                /**
                 * true: 等待消费
                 */
                if (person.flag) {
                    // TODO: await 用Lock锁的线程通讯.
                    //  condition.await(); 其实就是 让当前线程阻塞挂起,等待其他线程使用 condition.signal(); 通知这里可以继续向下执行
                    condition.await();
                }


                if (data == 0) {
                    person.username = "偶数";
                    person.age = 0;
                } else {
                    person.username = "奇数";
                    person.age = 1;
                }

                /**
                 * 依次改变data的值为: 偶数、奇数
                 */
                data = (data + 1) % 2;
                person.flag = false;

                // TODO:  signal 用Lock锁的线程通讯。 condition.signal(); 其实就是提前唤醒阻塞的线程,可以完成,尝试非阻塞式的获取锁,提升一些效率。
                condition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                /**
                 * 在finally中解锁。
                 */
                person.lock.unlock();
            }
        }

    }
}




public class ReadThread extends Thread {

    public Person person;
    public Condition condition;

    public ReadThread(Person person, Condition condition) {
        this.person = person;
        this.condition = condition;
    }

    @Override
    public void run() {

        while (true) {
            try {

                /**
                 * 上锁:
                 * 使用Lock锁之后,有个缺点,就是说,如果代码中间出现异常,如果没有特殊处理,下面的锁就一定不会解锁了。
                 * 那么处理这个问题也很简单,用try catch的finally。
                 *
                 * 注意这个锁的位置,一定要在上面。
                 */
                person.lock.lock();

                if (!person.flag) {
                    // TODO: condition.await(); 其实就是 让当前线程阻塞挂起,等待其他线程使用 condition.signal(); 通知这里可以继续向下执行
                    condition.await();
                }

                System.out.println(person.username + "," + person.age);
                person.flag = true;

                // TODO: condition.signal(); 其实就是提前唤醒阻塞的线程,可以完成,尝试非阻塞式的获取锁,提升一些效率。
                condition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                /**
                 * 在finally中解锁。
                 */
                person.lock.unlock();
            }
        }
    }
}



public class Test {

    public static void main(String[] args) {

        Person person = new Person();
        /**
         * 使用Lock锁后,线程之前通讯的方式用Condition类。
         * Condition底层原理也是 使用wait 和 notify,不过调用的方法改了。
         */
        Condition condition = person.lock.newCondition();

        WriteThread writeThread = new WriteThread(person, condition);
        ReadThread readThread = new ReadThread(person, condition);

        writeThread.start();
        readThread.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值