synchronized与Lock的区别用法!

提到锁,首先要明确一个概念:
1.线程与进程?
    一个简单的程序,最少需要一个进程而一个进程最少需要线程,所以关系是线程-->进程-->程序的大致构成结构,所以线程是
执行程序的最下单元,而进程是系统进行资源分配和调度的独立单元,所以以下是我们讨论的都是建立在线程的基础上

2.Thread的几个重要方法?
    a.start()方法,调用该方法开始执行线程
    b.stop()方法,调用该方法强制结束该线程执行
    c.join()方法,调用该方法等待线程结束
    d.sleep()方法,调用该方法线程进入等待
    e.run()方法,调用该方法直接执行线程的run()方法,这里调用start方法也可以运行线程,区别就是一个是由线程调度运行run()方法
    一个是直接调用了线程中的run()方法
    f.wait()方法和notify()方法呢?
            其实wait()方法和notify都是object()方法,不是thread方法
    g.wait()方法和notify()方法的区别?
            简单的来说wait()会释放锁对象而sleep()不会释放锁对象
            
3.线程的状态?
    新建状态:新建线程对象,并没有调用start()方法之前
    就绪状态:调用start()方法之后线程进入就绪状态,但是并不是说只要调用start()方法现象就能马上变为当前线程
    在变成当前线程之前都是就绪状态,值得一提的是,线程在睡眠和挂起中恢复的时候也会进入就绪状态
    运行状态:线程被设置为当前线程状态开始执行run()方法,就是就绪状态
    阻塞状态:线程被暂停,比如说调用sleep()方法后,线程就进入阻塞状态
    死亡状态:线程执行结束
    


4.锁的类型?
    可重入锁:在执行对象中,所有同步方法不用再次获得锁
    可中断锁:在等待获取锁的过程中可以中断
    公平锁:     按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁的权利
    读写锁:     对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步写
    

 5. synchronized与Lock的区别?

类别synchronizedLock
存在层次java的关键字,在jvm上是一个借口
锁的释放

1.已获取锁的线程执行完同步代码快

2.线程执行发生异常,jvm会让线程释放锁

在finally中必须释放锁,不然容易造成死锁
锁的获取假设A线程获得锁,B线程等,如果A线程阻塞.B线程一直等待分情况而定,lock有多个获取锁的方式,具体下面会说,大致就可以尝试获得锁,线程就可以一直等待
锁的状态无法判断可以判断
锁的类型可重入 不可中断 非公平可重入 可判断 可公平(两者皆可)
性能少量同步大量同步 

6.lock详解 (打开 idea ctlr+n 输入lock命令找到lock 源码)

lock接口中我们可以看出主要的方法,这些方法的功能从注释可以看出

lock():获取锁,如果锁被暂用则一直等待
unlock():释放锁
tryLock():注意返回类型是boolean,如果获取锁的时候被占用,则返回false,否则返回true
trylock(long time,timeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间
lockInterruptibly():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事

通过以上的解释,大致可以解释在上个部分 "锁的类型(lockInterruptibly())","锁状态(tryLock())" 等问题

来看下这边在网上找到的例子(下面是Lock一般使用的例子,注意ReentrantLock是Lock接口的实现。):

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by :Corey
 * 17:50 2019/4/8
 */
public class lockMethod {

    private Lock lock = new ReentrantLock();

    //需要参与同步方法
    private void method(Thread thread) {
        lock.lock();
        try {
            System.out.println("线程名" + thread.getName() + "获得了锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放量锁");
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        lockMethod lockMethod = new lockMethod();

        //线程1
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                lockMethod.method(Thread.currentThread());
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                lockMethod.method(Thread.currentThread());
            }
        }, "t2");

        t1.start();
        t2.start();

    }

}

执行结果:

tryLock() & tryLock(long time, TimeUnit unit) 顾明思议,就是尝试获取锁,可以加时间,tryLock(long time, TimeUnit unit)  能够响应中断.及支持对获取的中断,但是但尝试获取一个内部锁(synchronized)的操作是不能被中断,返回的是boolean类型这里可以进行判断,如果获取到了锁,则进行啥,若没有获取到锁执行啥,

测试代码:


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {

    private Lock lock = new ReentrantLock();
    /**
     *     true 表示 ReentrantLock 的公平锁
     */
    private ReentrantLock lock = new ReentrantLock(true);

    public static void main(String[] args) {
        //简单的使用
        test1();
        //trylock
        test2();
        //中断锁
        test3();
    }

    public static void test1() {
        LockTest lockTest = new LockTest();
        for (int i = 0; i < 10; i++) {
            //线程1
            new Thread(() -> {
                lockTest.method1(Thread.currentThread());
            }, i + "").start();
        }
    }

    //需要参与同步的方法
    private void method1(Thread thread) {
        //错误
//        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            System.out.println("线程名" + thread.getName() + "获得了锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放了锁");
            lock.unlock();
        }
    }

    public static void test2() {
        LockTest lockTest = new LockTest();
        for (int i = 0; i < 10; i++) {
            //线程1
            new Thread(() -> {
                lockTest.method2(Thread.currentThread());
            }, i + "").start();
        }
    }

    //需要参与同步的方法
    private void method2(Thread thread) {

//        尝试获取锁
        boolean b = lock.tryLock();

        //        尝试获取锁时间
//        boolean b = false;
//        try {
//            System.out.println("线程名" + thread.getName() + "尝试获取锁--");
//            b = lock.tryLock(2, TimeUnit.SECONDS);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        if (!b) {
            //未获取到锁
            System.out.println("线程名" + thread.getName() + "没有获取到锁,直接返回--");
            return;
        }
        //获取到锁
        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("线程名" + thread.getName() + "获得了锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放了锁");
            lock.unlock();
        }
    }

    public static void test3() {
        LockTest lockTest = new LockTest();
        //线程1
        Thread t1 = new Thread(() -> {
            try {
                lockTest.method3(Thread.currentThread());
            } catch (InterruptedException e) {
                System.out.println("线程名t1中断-----");
//                e.printStackTrace();
            }
        }, "t1");
        t1.start();
//线程1
        Thread t2 = new Thread(() -> {
            try {
                lockTest.method3(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("线程名t1执行中断");
        t1.interrupt();
    }

    //需要参与同步的方法
    private void method3(Thread thread) throws InterruptedException {
        lock.lockInterruptibly();
        //获取到锁
        System.out.println("线程名" + thread.getName() + "获得了锁");
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (Exception e) {
//            e.printStackTrace();
        } finally {
            System.out.println("线程名" + thread.getName() + "释放了锁");
            lock.unlock();
        }
    }

}

 

默认的ReentrantLock是不公平的锁

公平所,公平锁指的是谁先尝试获取锁,谁就能获取到锁,就是有可能的一个线程最先尝试获取锁,但是一直没有获取到锁,索取锁就是随机的,可以通过构造方法创建公平锁

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

非公平锁性能高于公平锁性能,首先,在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。而且,非公平锁能更充分的利用cpu的时间片,尽量的减少cpu空闲的状态时间。

ReadWriteLock(读写锁)

读写锁,跟lock接口没啥关系主要实现有ReentrantReadWriteLock

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

public class ReadWriteLockTest {

    private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    private static Integer count = 0;

    public static void main(String[] args) {
        ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
        for (int i = 0; i < 100; i++) {
            //从1到10的int型随数
            int j = (int) (1 + Math.random() * (10 - 1 + 1));
            if (j % 4 != 1) {
                //写操作
                new Thread("" + i) {
                    public void run() {
                        readWriteLockTest.get(Thread.currentThread());
                    }
                }.start();
            } else {
                //读操作
                int co = i;
                new Thread("" + i) {
                    public void run() {
                        readWriteLockTest.write(Thread.currentThread(), co);
                    }
                }.start();
            }
        }

    }

    public static void get(Thread thread) {
        rwl.readLock().lock();
        try {
            System.out.println("线程" + thread.getName() + "开始读操作...");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程" + thread.getName() + "读操作完毕..." + count);
        } finally {
            rwl.readLock().unlock();
        }
    }

    public static void write(Thread thread, int i) {
        rwl.writeLock().lock();
        try {
            System.out.println("线程" + thread.getName() + "开始写操作---------"+i);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count = i;
            System.out.println("线程" + thread.getName() + "开始写操作完成------"+i);
        } finally {
            rwl.writeLock().unlock();
        }
    }


}

执行结果

å¨è¿éæå¥å¾çæè¿°

开始读写操作,线程可以都进行读操作,要是有写操作,会等读操作都完成

Lock和synchronized的选择:

总的来说,lock和synchronized的选择有以下不同点:
    1.lock是一个接口,是jdk层面的实现,而synchronized是java中的关键字,是java的内置特性,是jvm层面的实现
    2.synchronized在发生异常的时,会自动释放线程占的锁,因此不会导致死锁现象发生,而lock在发生异常时候,如果没有
    unlock()去释放锁,则很可能造成死锁现象,因此使用lock时需要在finally快中释放锁
    3.lock可以让等待锁的线程响应中断,而使用synchronized时,等待的线程会一直等待下去,不能响应中断
    4.通过lock可以知道有没有成功获取锁,而synchronized却无法办到
    5.lock可以提高多个线程进行读操作的效率
    
在性能上说,如果竞争资源 不激烈,两者性能差不多,而当竞争资源非常激烈时候(既有大量线程同事竞争) 此时lock的性能要
远远优于synchronized

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值