【JavaSE】之JUC并发编程(上)(一)

简介: 【JavaSE】之JUC并发编程(上)

前言


本文为JUC并发编程相关知识,Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~


一、JUC概述


JUC指的是Java的并发工具包,包含以下三个包:


  • java.util.concurrent
  • java.util.concurrent.atomic:支持原子型操作
  • java.util.concurrent.locks:lock锁


二、进程与线程


1.进程


  • 程序执行的一次过程,一个进程包含一个或多个线程。进程是资源分配的单位。


2.线程


  • 可以指程序执行过程中,负责实现某个功能的单位。线程是CPU调度和执行的单位。


3.并发


  • 同一时刻,多个线程交替执行。(一个CPU交替执行线程)。


4.并行


  • 同一时刻,多个线程同时执行。(多个CPU同时执行多个线程)。
# 获取cpu的核数(cpu密集型;io密集型)
System.out.println(Runtime.getRuntime().availableProcessors());


5.并发编程的本质


  • 并发编程的本质是充分利用cpu资源。


三、多线程回顾


1.线程的几种状态

    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
         // 新生
        NEW,
        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
         // 运行
        RUNNABLE,
        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
         // 阻塞
        BLOCKED,
        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
         // 等待,死死的等待
        WAITING,
        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
         // 超时等待
        TIMED_WAITING,
        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
         // 终止
        TERMINATED;
    }

2.sleep和wait的区别


sleep是Thread类的本地方法;wait是Object类的方法。

sleep不释放锁;wait释放锁。

sleep不需要和synchronized关键字一起使用;wait必须和synchronized代码块一起使用。

sleep不需要被唤醒(时间到了自动退出阻塞);wait需要被唤醒。

sleep一般用于当前线程休眠,或者轮循暂停操作;wait则多用于多线程之间的通信。


四、Lock锁


1.传统的synchronized


synchronized中文意思是同步,也称之为”同步锁“。

synchronized的作用是保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。

synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。

在JDK1.5之前synchronized是一个重量级锁,相对于j.u.c.Lock,它会显得那么笨重,随着Javs SE 1.6对synchronized进行的各种优化后,synchronized并不会显得那么重了。


synchronized的作用主要有三个:


原子性:确保线程互斥地访问同步代码;

可见性:保证共享变量的修改能够及时可见,其实是通过Java内存模型中的“对一个变量unlock操作之前,必须要同步到主内存中;如果对一个变量进行lock操作,则将会清空工作内存中此变量的值,在执行引擎使用此变量前,需要重新从主内存中load操作或assign操作初始化变量值”来保证的;

有序性:有效解决重排序问题,即 “一个unlock操作先行发生(happen-before)于后面对同一个锁的lock操作”;


2.公平锁和非公平锁(锁的底层)


公平锁:十分公平,不能插队。


非公平锁:十分不公平,可以插队。(默认非公平锁)


3.Lock锁


Lock锁是一个接口,他有三个实现类:

ReentrantLock类

ReentrantReadWriteLock.ReadLock

ReentrantReadWriteLock.WriteLock


4.Lock锁和synchronized的区别


Synchronized是内置Java关键字;Lock是一个Java类。

Synchronized无法判断获取锁的状态;Lock可以判断是否获取到了锁。(boolean b = lock.tryLock();)

Synchronized会自动释放锁;Lock必须要手动释放锁,如果不释放锁,死锁。

Synchronized线程1获得锁阻塞时,线程2会一直等待下去;Lock锁线程1获得锁阻塞时,线程2等待足够长的时间后中断等待,去做其他的事。

Synchronized可重入锁,不可以中断的,非公平;Lock,可重入锁,可以判断锁,非公平(可以自己设置)。

lock.lockInterruptibly();方法:当两个线程同时通过该方法想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。

Synchronized适合锁少量的代码同步问题;Lock适合锁大量的同步代码。


5.生产消费者


生产者和消费者问题:synchronized版

public class Demo04 {
 public static void main(String[] args) {
     Data data = new Data();
     new Thread(() -> {
         for (int i = 0; i < 10; i++) {
             try {
                 data.increment();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }, "A").start();
     new Thread(() -> {
         for (int i = 0; i < 10; i++) {
             try {
                 data.decrement();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }, "B").start();
 }
}
// 判断等待,业务,通知
class Data {
 private int i = 0;
 // +1
 public synchronized void increment() throws InterruptedException {
     if (i != 0) {
         this.wait();
     }
     i++;
     System.out.println(Thread.currentThread().getName() + "=>" + i);
     // 通知其他线程我+1完成
     this.notifyAll();
 }
 // -1
 public synchronized void decrement() throws InterruptedException {
     if (i==0){
         this.wait();
     }
     i--;
     System.out.println(Thread.currentThread().getName() + "=>" + i);
     // 通知其他线程,我-1完毕
     this.notifyAll();
 }
}


问题存在:A、B、C、D四个线程!虚假唤醒问题

if改成while解决虚假唤醒

 public class Demo04 {
     public static void main(String[] args) {
         Data data = new Data();
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.increment();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "A").start();
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.decrement();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "B").start();
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.increment();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "C").start();
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.decrement();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "D").start();
     }
 }
 // 判断等待,业务,通知
 class Data {
     private int i = 0;
     // +1
     public synchronized void increment() throws InterruptedException {
         while (i != 0) {
             this.wait();
         }
         i++;
         System.out.println(Thread.currentThread().getName() + "=>" + i);
         // 通知其他线程我+1完成
         this.notifyAll();
     }
     // -1
     public synchronized void decrement() throws InterruptedException {
         while (i==0){
             this.wait();
         }
         i--;
         System.out.println(Thread.currentThread().getName() + "=>" + i);
         // 通知其他线程,我-1完毕
         this.notifyAll();
     }
 }

生产者和消费者问题:JUC版

public class Demo04 {
 public static void main(String[] args) {
     Data data = new Data();
     new Thread(() -> {
         for (int i = 0; i < 10; i++) {
             try {
                 data.increment();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }, "A").start();
     new Thread(() -> {
         for (int i = 0; i < 10; i++) {
             try {
                 data.decrement();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }, "B").start();
     new Thread(() -> {
         for (int i = 0; i < 10; i++) {
             try {
                 data.increment();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }, "C").start();
     new Thread(() -> {
         for (int i = 0; i < 10; i++) {
             try {
                 data.decrement();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }, "D").start();
 }
}
// 判断等待,业务,通知
class Data {
 private int i = 0;
 Lock lock = new ReentrantLock();
 Condition condition = lock.newCondition();
 // +1
 public  void increment() throws InterruptedException {
     lock.lock();
     try {
         while (i != 0) {
             condition.await();
         }
         i++;
         System.out.println(Thread.currentThread().getName() + "=>" + i);
         // 通知其他线程我+1完成
         condition.signalAll();
     } catch (InterruptedException e) {
         e.printStackTrace();
     } finally {
         lock.unlock();
     }
 }
 // -1
 public void decrement() throws InterruptedException {
     lock.lock();
     try {
         while (i==0){
             condition.await();
         }
         i--;
         System.out.println(Thread.currentThread().getName() + "=>" + i);
         // 通知其他线程,我-1完毕
         condition.signalAll();
     } catch (InterruptedException e) {
         e.printStackTrace();
     } finally {
         lock.unlock();
     }
 }
}


6.Condition实现精准通知唤醒

public class Demo05 {
    public static void main(String[] args) {
        Data01 data01 = new Data01();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data01.A();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data01.B();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data01.C();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }
}
// 判断等待,业务,通知
//A执行完调用B,B执行完调用C,C执行完调用A
class Data01 {
    private int num = 1;// 1A 2B 3C
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    public void A() throws InterruptedException {
        lock.lock();
        try {
            // 业务代码,判断=>执行=>通知!
            while (num!=1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAA");
            num = 2;
            // 唤醒指定的线程,B
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void B() throws InterruptedException {
        lock.lock();
        try {
            while (num!=2){
                condition2.await();
            }
            num = 3;
            System.out.println(Thread.currentThread().getName()+"=>BBBBB");
            // 唤醒指定的线程,C
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void C() throws InterruptedException {
        lock.lock();
        try {
            while (num!=3){
                condition3.await();
            }
            num = 1;
            System.out.println(Thread.currentThread().getName()+"=>CCCCC");
            // 唤醒指定的线程,A
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}


相关文章
|
Java 调度 Maven
JUC并发编程【java提高】1
JUC并发编程【java提高】1
98 0
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
Java 调度 数据安全/隐私保护
JUC并发编程【java提高】4
JUC并发编程【java提高】4
59 0
|
SQL 存储 缓存
JUC并发编程【java提高】3
JUC并发编程【java提高】3
51 0
|
安全 算法 Java
JUC第九讲:类汇总和学习指南
JUC第九讲:类汇总和学习指南
|
缓存 Java 数据库连接
JUC并发编程【java提高】2
JUC并发编程【java提高】2
50 0
|
存储 前端开发 算法
【JavaSE】之JUC并发编程(下)(一)
【JavaSE】之JUC并发编程(下)(一)
【JavaSE】之JUC并发编程(下)(一)
|
存储 SQL 设计模式
【JavaSE】之JUC并发编程(下)(二)
【JavaSE】之JUC并发编程(下)(二)
【JavaSE】之JUC并发编程(下)(二)
|
安全 Java
【JavaSE】之JUC并发编程(上)(二)
【JavaSE】之JUC并发编程(上)(二)
|
安全 Java API
史上最全的Java并发系列之Java中的锁的使用和实现介绍(一)
前言 文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820… 种一棵树最好的时间是十年前,其次是现在
399 0