JUC(
java.util.concurrent
) 在 Java 5.0 提供了JUC
包,在此包中增加了在并发编程中很常用的工具类,用于定义类似于线程的自定义子系统,包括线程池,异步 IO 和轻量级任务框架;还提供了设计用于多线程上下文中的 Collection 实现等
学习juc,主要就是这三个包的知识点。
Thread、Runnable没有返回值,效率没有Callable
高,可以抛异常。
线程的基本方法:
getName()
: 获取当前线程的名字join()
: 其他线程阻塞直至该线程执行完毕sleep(int)
: 使该线程睡眠毫秒数yeild()
: 让出cpu,让cpu重新调度getPriority()
: 返回该线程的优先级getState()
: 返回该线程的状态stop()
: 线程停止--已废弃
!Lock:

进程:一个程序就是一个进程,比如:QQ.exe。一个进程包含多个线程,但至少有一个线程
java中默认有几个线程? 2个,main和GC
线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行。比如,打开idea进程,敲代码是一个线程、自动保存又是一个线程。
Java中开启线程的方式:Thread、Runnable、Callable、线程池
线程的几种状态:
public enum State {
// 新生状态
NEW,
// 运行状态
RUNNABLE,
// 被阻塞等待监视器锁定的线程处于此状态
BLOCKED,
// 正在等待另一个线程执行特定动作的线程处于此状态
WAITING,
// 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
TIMED_WAITING,
// 已退出的线程处于此状态
TERMINATED;
}
Java能开启线程吗? 不能
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
// 本地方法,Java无法直接操作硬件,底层是C++
private native void start0();
重点是这句:private native void start0();
,这是个本地方法,底层是c++。
注:更详细的两者对比可点击查看
通俗解释:
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你
不支持并发也不支持并行
。 你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发
。 你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行
。
并发
的关键是你有处理多个任务
的能力,不一定要同时。
并行
的关键是你有同时处理多个任务
的能力。
所以它们最关键的点就是:是否是『同时
』。
并发:多线程同时操作同一个资源,并发的本质就是充分利用CPU。
并行:多个程序同时运行
// 获取cpu的核数
Runtime.getRuntime().availableProcessors();
synchronized
比较:Synchronized 是内置的java关键字;
Lock 是一个java类。
synchronized会自动释放锁;
lock需要手动释放锁,需要 lock() 和 unlock() 方法配合 try / finally 语句块来完成。
synchronized 不可中断,除非抛出异常或者正常运行完成;
ReentrantLock 可中断,设置超时方法 tryLock(long timeout, TimeUnit unit)lockInterruptibly() 放代码块这,调用 interrupt() 方法可中断
synchronized 非公平锁;
ReentrantLock 两者都可以,默认非公平锁,构造方法可以传入 boolean 值,true 为公平锁,false 为非公平锁
Lock可以精确唤醒,而不是像 synchronized 要么随机唤醒一个线程要么唤醒全部线程。
/**
* Copyright (C), 2015-2020, https://www.liuwenxu.com/
* FileName: SynchronizedTest
* Author: liuwenxu
* Date: 2020/7/10 5:42 下午
* Description: 多线程synchronized 买票案例
*/
public class SynchronizedTest {
public static void main(String[] args) {
Tickets tickets = new Tickets();
new Thread(() -> {for (int i = 0; i < 40; i++) tickets.sell();}, "A").start();
new Thread(() -> {for (int i = 0; i < 40; i++) tickets.sell();}, "B").start();
new Thread(() -> { for (int i = 0; i < 40; i++) tickets.sell();}, "C").start();
}
}
class Tickets {
private Integer num = 30;
// 队列
public synchronized void sell() {
if (num > 0) {
System.out.println("窗口" + Thread.currentThread().getName()
+ "卖出第" + (num--) + "张票,还剩:" + num + "张");
}
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Copyright (C), 2015-2020, https://www.liuwenxu.com/
* FileName: LockTest
* Author: liuwenxu
* Date: 2020/7/10 5:42 下午
* Description: 多线程lock 卖票案例
*/
public class LockTest {
public static void main(String[] args) {
Tickets2 tickets = new Tickets2();
new Thread(()->{ for (int i = 0; i < 40; i++) tickets.sell(); },"A").start();
new Thread(()->{ for (int i = 0; i < 40; i++) tickets.sell(); },"B").start();
new Thread(()->{ for (int i = 0; i < 40; i++) tickets.sell(); },"C").start();
}
}
class Tickets2 {
private Integer num = 30;
// lock三部曲
// Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
Lock l = new ReentrantLock();
public void sell() {
l.lock();
try {
if (num > 0) {
System.out.println("窗口" + Thread.currentThread().getName() + "卖出第" + (31-(num--)) + "张票,还剩:" + num + "张");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
l.unlock();
}
}
}
Q.E.D.