1,什么是 JUC
1.1 JUC简介
JUC 就是java.util.concurrent 工具包的简称,这一个专门用来处理线程的工具包,JDK1.5开始出现
1.2 进程与线程
**进程(Process):**是系统进行资源分配和调度的基本单位,比如QQ启动就是一个进程。
**线程(Thread):**是操作系统能够进行运算调度的最小单位,是程序执行的最小单位,它被包含在进程中,比如QQ中的各个功能,都是不同的线程。
1.3 线程的状态
在Thread类中枚举了线程的6种状态;
public enum State {
NEW,//新建状态
RUNNABLE,//准备就绪
BLOCKED,//阻塞状态
WAITING,//等待状态:不见不散
TIMED_WAITING,//等待状态:过期不候
TERMINATED;//终止态
}
wait/sleep的区别:
- sleep是Thread的静态方法;wait是Object类的方法,任何对象实例都可以调用
- sleep不会释放锁,它也不需要占有锁;wait会释放锁,但调用wait方法的前提是当前线程已经占有锁(即代码要在synchronized中)
- 它们都可以被interrupted方法中断
1.4 并发和并行
- 串行:一次只能执行一个任务,只有当前任务执行完成才能执行下一个
- 并行:多个任务同时执行,最后再进行汇总;比如:泡方便面,电水壶烧水,一边放调料包
- 并发:同一时刻多个线程访问同一个资源,多个线程对一个点;例子:春运抢票,电商秒杀
1.5 管程
管程(monitor)是保证了同一时刻只有一个进程在管程内活动,JVM中同步是基于进入和退出管程对象来实现的,每一个对象都会有一个管程对象,管程对象会随着java对象一同创建和销毁
执行线程首先要持有管程对象,然后执行完后再释放管程对象,
1.6 用户线程和守护线程
**用户线程:**平时自定义的线程
**守护线程:**运行在后台,是一种特殊的线程,比如垃圾回收
当main主线程结束后,用户线程还在运行,则JVM存活
如果没有用户线程,只剩守护线程,则JVM结束
可以通过Thread的setDaemon(true)方法把用户线程变为守护线程
2,Lock接口
2.1 Synchronized
synchronized 是 Java 中的关键字,是一种同步锁。它修饰的对象有以下几种:
-
修饰一个代码块:被修饰的代码块称为同步语句块,其作用的范围是大括号{}
括起来的代码,作用的对象是调用这个代码块的对象;
-
修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用
的对象是调用这个方法的对象;
虽然可以使用 synchronized 来定义方法,但 synchronized 并不属于方法定义的一部分,因此,synchronized 关键字不能被继承。如果在父类中的某个方
法使用了 synchronized 关键字,而在子类中覆盖了这个方法,在子类中的这
个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上
synchronized 关键字才可以。当然,还可以在子类方法中调用父类中相应的方
法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,
子类的方法也就相当于同步了。
-
修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的
所有对象;
-
修饰一个类,其作用的范围是 synchronized 后面括号括起来的部分,作用主
的对象是这个类的所有对象。
Lock和synchronized不同:
- Lock是一个接口,而synchronized是java中的一个关键字,synchronized是内置语言的实现
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象;但Lock在发生异常时,必须手动释放锁,很可能造成死锁现象,因此必须在finally中手动释放锁
- Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能响应中断
- Lock可以知道线程有没有成功获取到锁,而synchronized则无法办到
- Lock可以提高多个线程执行读操作的效率
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源
非常激烈时(即有大量线程同时竞争),此时 Lock 的性能要远远优于synchronized
多线程编程步骤:
- 创建资源类,创建属性和操作方法
- 创建多线程调用资源类的方法
- 为了控制多线程执行顺序,在操作方法中:判断,干活,通知
3,线程间通信
场景—两个线程,一个线程对当前数值加 1,另一个线程对当前数值减 1,要求用线程间通信
Synchronized:
//创建资源类
class Num{
private int number = 0;
public synchronized void incr() throws InterruptedException {
while (number != 0){
//这里一定要用while而不能用if,if会导致假唤醒状态
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+":"+number);
notifyAll();
}
public synchronized void decr() throws InterruptedException {
while (number == 0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+":"+number);
notifyAll();
}
}
public class SynchronizedDemo {
public static void main(String[] args) {
Num num = new Num();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}
Lock:
//创建资源类
class Num1{
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void incr() throws InterruptedException {
lock.lock();
try {
while (number != 0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+":"+number);
condition.signalAll();
} finally {
lock.unlock();
}
}
public void decr() throws InterruptedException {
lock.lock();
try {
while (number == 0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+":"+number);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public class LockDemo {
public static void main(String[] args) {
Num1 num = new Num1();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
num.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}
定制线程通信顺序:
1->5,1->10,1->15 执行三轮
//资源类
class Resource{
private int flag = 1;//标志位
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void circle5(int loop) throws InterruptedException {
lock.lock();
try {
while (flag != 1){
c1.await();
}
for (int i = 1; i < 6; i++) {
System.out.println(Thread.currentThread().getName()+":"&