超链接:
java并发
java并发2
1.进程、线程
2.并行、并发
- 并行:多个事件在同一时刻发生
- 并发:多个事件在同一时间间隔发生
3.同步、异步
- 同步:需要等待另一个线程的结果返回,才能继续运行
- 异步:不需要等待另一个线程的结果,就可以继续运行
默认,主线程
方法一,直接使用 Thread匿名内部类,创建Thread的子类,重写run()方法
// 创建线程
// 构造方法的参数是给线程指定的名字
Thread t1 = new Thread("t1") {
@Override
// run 方法内实现了要执行的任务
public void run() {
log.debug("hello");
}
};
// 启动线程
t1.start();
方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开
- Thread 代表线程
- Runnable 可运行的任务(线程要执行的代码)
// 创建任务对象
Runnable task2 = new Runnable() {
@Override
public void run() {
log.debug("hello");
}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐给线程起个名字
Thread t2 = new Thread(task2, "t2");
t2.start();
lambda写法
() -> {},相当于:创建了子类/实现类,重写了方法,并new了一个对象。三步简化为一步。
Runnable task2 = () -> {log.debug("hello");}
方法三,FutureTask 配合 Thread
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
使用get()得到线程返回的结果
public static void main(String[] args) {
// 返回100
FutureTask futureTask = new FutureTask<>(new Callable() {
@Override
public Integer call() throws Exception {
log.debug("running...");
Thread.sleep(1000);
return 100;
}
});
// 主线程会阻塞,等待线程执行完毕的结果
Thread t = new Thread(futureTask,"t1").start();
log.debug("主线程");
log.debug("{}",futureTask.get());//主线程使用线程结果
//{}是占位符,结果会拼在大括号的位置
}
三、线程的运行原理
观察多个线程同时运行:
1.交替执行
2.多个线程的执行先后,不受程序员控制
JVM由堆、栈、方法区组成,栈由多个栈帧组成。
栈用来存放线程,栈帧用来存放方法。
每个线程都有它自己的程序计数器,是线程私有的。
程序计数器是用于存放下一条指令所在单元的地址。
运行Testframes.java的整体流程:
1.类加载。将.class文件加载到jvm的方法区中。
2.启动栈。运行main主线程。
3.分配栈帧。运行主线程中的各个方法。
…
因为一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程
四、线程的常用方法
join():等待另一个线程运行结束。结束后,可能去拿它的结果,用于线程间的通信。可以一直等待它结束,或者只等待一段时间。
yield():让出当前线程的CPU使用,类似于sleep()
数字大,优先级高
不推荐的方法:stop()停止线程、suspend()挂起/暂停线程、resume()恢复线程
sleep()
1.调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
2.其它线程可以使用 interrupt 方法打断正在睡眠的线程,那么被打断的线程这时就会抛出 InterruptedException异常
3.睡眠结束后的线程未必会立刻执行
4.建议用 TimeUnit 的 sleep() 代替 Thread 的 sleep()来获得更好的可读性
yield()
1.调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态
2.yield()后的线程仍可能会继续执行
小结
yield使cpu调用其它线程,但是cpu可能会再分配时间片给该线程;而sleep需要等过了休眠时间之后才有可能被分配cpu时间片
1.打断 sleep,wait,join 的线程
2.打断正常运行的线程
打断正常运行的线程, 线程并不会暂停。
可以使用打断标记isInterred(),做别的处理。
sleep,join,yield,interrupted是Thread类中的方法
wait/notify是object中的方法
sleep 不释放锁、释放cpu
join 释放锁、抢占cpu
yiled 不释放锁、释放cpu
wait 释放锁、释放cpu
说法一:5种状态
是从操作系统的层面划分的
说法二:6种状态
是从 Java API 的层面划分的
即根据 Thread.State 枚举,分为六种状态
new:创建了线程,但没调用start()方法
runnable:包括就绪、运行、阻塞(指IO阻塞)
blocked:synchronized锁,得不到锁而阻塞
waiting:join()
timed_waiting:sleep()
terminated:线程运行完毕
可以让多线程对共享资源进行读写操作的代码块。
3. synchronized即‘对象锁’
互斥
同一时刻最多只有一个线程持有对象锁。此时,拿着锁的此线程就可以访问临界区的代码。
语法:
synchronized(对象) // 线程1获得锁,那么线程2的状态是blocked
{
临界区
}
synchronized原理:
synchronized实际上利用对象保证了临界区代码的原子性,临界区内的代码在外界看来是不可分割的,不会被线程切换所打断
图解:
同学1得到cpu的时间片,得到锁,进入。同学2、3得到cpu的时间片,得不到锁,blocked阻塞。注意,阻塞状态是不会分到cpu的时间片的。同学1的时间片用完,但他仍持有锁,直到再次得到时间片,继续执行。同学1执行完毕,释放锁,唤醒另外的同学…
过程式的代码
@Slf4j
public class Test1 {
static int count = 0;
static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock) {
count++;
}
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock) {
count--;
}
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("{}", count);
}
}
改进:使用面向对象思路的锁
让共享资源成为一个类,操作加锁。
@Slf4j
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Room room = new Room();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
room.increment();
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
room.decrement();
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("{}", room.getCount());
}
}
class Room {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public void decrement() {
synchronized (this) {
count--;
}
}
public int getCount() { //获取也要加锁
synchronized (this) {
return count;
}
}
}
synchronized的补充写法
非静态方法:this对象锁
class Test {
public synchronized void test() { }
}
//等价于
class Test {
public void test() {
synchronized (this) { }
}
}
静态方法:类对象锁
class Test {
public synchronized static void test() { }
}
// 等价于
class Test {
public static void test() {
synchronized (Test.class) { }
}
}
管程——悲观锁(阻塞)
JMM
原子性
可见性
有序性
线程池
JUC:
Lock
Semaphore
CountdownLatch
CyclicBarrier
ConcurrentHashMap
ConcurrentlinkedQueue
BlockingQueue
CopyOnWriteArrayList
disruptor
guava
CompletetableFuture
反应式:
project-reactor
spring webflux
私有
Actor——弱一致性
akka
函数式编程
并行编程:映射、归约
Balking
Guarded Suspension
控制顺序
两阶段退出
WorkThread
Thread per Message
生产者/消费者



