一点点JUC的小姿势
1 JUC
JUC就是java.util.concurrent下面的类包,专门用于多线程的开发。
1.1 并发与并行
- 并发
多线程操作同一个资源。
- CPU 只有一核,模拟出来多条线程,天下武功,唯快不破。那么我们就可以使用CPU快速交替,来模拟多线程。
- 并发编程的本质:充分利用CPU的资源!
- 并行
并行: 多个人一起行走
- CPU多核,多个线程可以同时执行。 我们可以使用线程池!
1.2 线程的状态
public enum State {
//新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}
1.3 wait/sleep
1、这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类。
sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。
2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
Thread.Sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。
3、使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
synchronized(x){
x.notify()
//或者wait()
}
2 Lock锁
2.1 传统的 synchronized
public synchronized void sale(){
if (sum > 0)
System.out.println(Thread.currentThread().getName() + "获得了第:"+ sum + "张票,此时还剩 " + --sum);
}
2.2 Synchronized 和 Lock 的区别
- Synchronized 是Java的内置关键字,Lock是一个Java类
- Synchronized 无法判断获取锁的状态,而Lock可以
- Synchronized 会自动释放锁,Lock必须手动释放,否则死锁
- Synchronized 会造成阻塞,Lock不一定会
- Synchronized 可重入锁,不可以中断,非公平; Lock 可重入锁,可以判断锁,公平性可以自定义
- Synchronized 适合少量代码的同步问题,Lock适合锁大量的同步代码
2.3 精准控制线程顺序
public class ProductAndConsumer02 {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {for (int i = 0; i < 10; i++) data.printA();},"A").start();
new Thread(() -> {for (int i = 0; i < 10; i++) data.printB();},"B").start();
new Thread(() -> {for (int i = 0; i < 10; i++) data.printC();},"C").start();
}
}
class Data{
private static int num = 1;
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void printA(){
lock.lock();
try {
while (num != 1){
condition1.await();
}
System.out.println(Thread.currentThread().getName() + ": "+ "AAAAAAA");
//num = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
System.out.println("B lock");
lock.lock();
try {
if (num != 2){
condition2.await();
}
System.out.println(Thread.currentThread().getName() + ": "+ "BBBBBBB");
num = 3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (num != 3){
condition3.await();
}
System.out.println(Thread.currentThread().getName() + ": "+ "CCCCCCC");
num = 1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}