美文网首页
JUC(一)

JUC(一)

作者: iMikasa_ | 来源:发表于2021-08-09 20:04 被阅读0次

写在前面

(并发编程)JUC的东西太多,一篇简书肯定是记录不完的。在下文中也能看出来我处处(挖坑),把一些东西抽离出来,写成另一篇简书,日后会慢慢填坑的。本文也是在学习阶段记录的,我通过查阅资料例如:http://ifeve.com/ 和自己试验着敲着测试代码,整理出自己理解的JUC的一些知识。

并发编程之美?

什么是JUC

java.util.concurrent包

线程和进程

进程:一个跑起来的程序(一个进程可以包含多个线程)
线程:Thread、Runable、Callable

并发、并行

1.并发:CPU 一核,模拟多条线程,快速交替执行
2.并行:CPU多核,多个线程同时执行

并发编程的本质:充分利用CPU的资源

线程的几个状态

线程状态

wait和sleep区别

1.来自不同的类,wait是Object的方法,sleep是Thread的方法
建议sleep使用TimeUnit.SECONDS.sleep(1);
2.wait会释放锁,sleep不会

我的理解

一个程序运行多个线程本身是没有问题的
问题出在多个线程访问共享资源
多个线程读共享资源其实也没有问题
在多个线程对共享资源读写操作时发生指令交错,就会出现问题
一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件

解决办法之一就是synchronized

synchronized的使用

在应用Sychronized关键字时需要把握如下注意点:

  • 一把锁只能同时被一个线程获取,没有获得锁的线程只能等待;
  • 每个实例都对应有自己的一把锁(this),不同实例之间互不影响;例如:锁对象是*.class以及synchronized修饰的是static方法的时候,所有对象公用同一把锁
  • synchronized修饰的方法,无论方法正常执行完毕还是抛出异常,都会释放锁

继续探索


如果一个代码块被 synchronized 修饰了,当一个线程获取了对应的锁,并执 行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里 获取锁的线程释放锁只会有两种情况:

  • 获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
  • 线程执行发生异常,此时JVM 会让线程自动释放锁。
      那么如果这个获取锁的线程由于要等待 IO 或者其他原因(比如调用 sleep 方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一 下,这多么影响程序执行效率。
    因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过 Lock 就可以办到。

Lock

Lock 锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock 提供了比 synchronized 更多的功能。

Lock 与的 Synchronized 区别:

  • Lock 不是 Java 语言内置的,synchronized是 Java 语言的关键字,因此是内 置特性。Lock 是一个类,通过这个类可以实现同步访问;
  • Lock 和 synchronized 有一点非常大的不同,采用 synchronized不需要用户 去手动释放锁,当 synchronized 方法或者synchronized 代码块执行完之后, 系统会自动让线程释放对锁的占用;而 Lock 则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

Lock接口及其实现类

public interface Lock {

    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}
Lock类图
how to use
  • lock(): 加锁
  • unlock(): 解锁
  • tryLock(): 尝试获取锁,返回一个boolean值
  • tryLock(long,TimeUtil): 尝试获取锁,可以设置超时

lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他 线程获取,则进行等待。
采用 Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一 般来说,使用 Lock 必须在 try{}catch{}块中进行,并且将释放锁的操作放在 finally 块中进行,以保证锁一定被被释放,防止死锁的发生。通常使用 Lock来进行同步的话,是以下面这种形式去使用的:

        Lock lock = ...;
        lock.lock();
        try {
            // 处理任务
        } catch (Exception e) {
        } finally {
            // 释放锁
            lock.unlock();
        }

Lock的实现类及其后续记录,之后填坑

相关文章

网友评论

      本文标题:JUC(一)

      本文链接:https://www.haomeiwen.com/subject/mzyovltx.html