持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情
前置知识
JUC是什么?
java.util.concurrent
的简称,是java5开始提供的并发编程的工具类
进程是什么?
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体
所以进程是操作系统分配资源的最小单位,是一个可运行程序的实例,是线程的容器
shift + alt + esc
打开任务管理器,就能看到当前系统正在运行的一排排进程了
线程是什么?
线程(Thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
(Linux下没有真正的线程,只有LWP,但Windows是有的哦)
所以线程是操作系统能调度的最小单位,可以共享进程中的全部资源,一个进程可以同时并行多条线程
Java线程的状态
打开Thread.State
枚举类
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;
}
- NEW 线程创建但未启动的状态
- RUNNABLE 处于可运行的状态
- BLOCKED 阻塞状态
- WAITING 等待状态
- TIMED-WAITING 具有指定等待时间的等待线程的线程状态
- TERMINATED 终止状态
wait和sleep的区别
- 调用方式 wait是Object的对象方法,Sleep是线程类Thread的静态方法
- 是否会释放当前锁 sleep会不会释放当前线程占有的锁,如果wait在同步块/方法内则会释放锁
并发和并行的区别
并发就是多个线程去使用同一个资源
并行是多个线程同时工作再汇总
管程是什么?
就是锁(Lock)
操作系统中,有两种方法来实现锁机制, 分别是信号量(Semaphere)和管程(Minitor),JDK
中的锁就是通过管程实现的
用户线程和守护线程有什么区别?
都可以通过用户创建与使用,区别是守护线程随主线程结束而结束,而用户线程的生命周期和主线程不同步
Thread类提供了两个对象方法来设置或判断守护线程
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
public final boolean isDaemon() {
return daemon;
}
同步代码块/方法与锁
synchronizad
可以作用于一段代码块上,一个方法上等,本质是同步锁
当一个线程获得该同步锁时,其他试图访问该对象的线程将被阻塞,这个基础就不再多讲了,不会的同学可以去看看基础教程
卖票例子
class Ticket {
private int ticket = 50;
public synchronized void sale() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "::" + ticket--);
}
}
}
@Test
public void sale() {
Ticket ticket = new Ticket();
Runnable runnable = () -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
};
new Thread(runnable, "t3").start();
new Thread(runnable, "t1").start();
new Thread(runnable, "t2").start();
}
Lock
接口提供了比synchronizad
更广泛的锁定操作
需要手动上锁以及释放锁
锁类型:
- ReentrantLock 可重入锁
- ReentrantReadWriteLock.ReadLock
- ReentrantReadWriteLock.WeriteLock
卖票例子2
public synchronized void sale() {
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "::" + ticket--);
}
lock.unlock();
}
线程通信wait,notify/notifyAll
public synchronized void incr() throws InterruptedException {
while (num != 0) {
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"::"+num);
this.notifyAll();
}
wait方法可能会有虚假唤醒的可能,因为在哪里沉睡就会在哪里醒来,所以if判断只会执行一次,所以要用while()包裹,源码注释如下:
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}