前言
本文为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(); } } }