java线程
为什么会出现多线程?
进程是程序执行的实体,每一个进程都是一个应用程序,cpu有多核,每个核心只能处理一件事,当多个进程,也就是多个程序运行的时候,cpu一般会通过时间片轮转调度的算法来实现多个进程的同时运行
若两个任务需要同时运行,必须要运行两个进程,由于每个进程会有自己的独立的内存空间,进程之间的通信变得很麻烦,而且不同进程之间执行会产生上下文切换,比较耗时,因此会提出能否在进程中执行多个任务?
线程问世, 一个进程会包含多个线程,线程是单一的顺序控制流程,到此,线程就变成了程序执行的最小单元,各线程之间可以共享该进程所在的内存空间,线程之间上下文切换也快于进程
一般情况下,main方法是单线程的执行,也就是计算、运行是同步的,如果我们想并行的计算,也就是异步计算,应该如何?这就需要多线程
线程怎么用?
这是一个例子,主线程先抢占到cpu资源
//code
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50; i++) {
System.out.println("线程A" + i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50; i++) {
System.out.println("线程B" + i);
}
});
t1.start();
t2.start();
}
}
//result
线程A0
线程B0
线程A1
线程A2
线程A3
线程B1
线程A4
......
线程生命周期
线程处于运行状态下,下一个状态会是:就绪态、阻塞态、终止态
// code: 对于处于线程中断信号,不予处理,继续运行
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("线程开始运行");
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("发现中断信号,不管,继续运行");
Thread.interrupted(); //中断标记复位,也就是不管中断信号
}
}
});
t1.start();
try {
Thread.sleep(3000);
t1.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// code:线程暂停后继续运行,不推荐,会牵扯到死锁
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("线程开始运行");
Thread.currentThread().suspend();
System.out.println("线程继续运行");
});
t1.start();
try {
Thread.sleep(3000);
t1.resume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程优先级
因为资源问题,java内部事采用的线程抢占式调度,也就是优先级别越高,越优先使用cpu资源,一般分为三种:最低、最高、常规
// code:在某个执行时可以让位给其他线程
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("线程A开始运行");
for (int i = 0; i < 50; i++) {
if (i % 5 == 0) {
System.out.println("让位");
Thread.yield();
}
}
System.out.println("线程A结束");
});
Thread t2 = new Thread(() -> {
System.out.println("线程B开始运行");
for (int i = 0; i < 50; i++) {
System.out.println("线程B执行" + i);
}
System.out.println("线程B执行完毕");
});
t1.start();
t2.start();
}
}
// result
线程A开始运行
让位
线程B开始运行
让位
让位
线程B执行0
线程B执行1
线程B执行2
线程B执行3
线程B执行4
线程B执行5
让位
......
某个线程运行时,产生某个条件时,可以让另外一个线程先执行
// code:线程B执行=10时,会等待执行,让线程A全部执行完再去执行剩下的
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("线程A开始运行");
for (int i = 0; i < 50; i++) {
System.out.println("A计算" + i);
}
System.out.println("线程A结束");
});
Thread t2 = new Thread(() -> {
System.out.println("线程B开始运行");
for (int i = 0; i < 50; i++) {
System.out.println("线程B执行" + i);
if (i == 10) {
try {
System.out.println("线程A加入");
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("线程B执行完毕");
});
t1.start();
t2.start();
}
}
线程同步
对于一公共线程可访问变量,对其修改不同步会导致数值异常,所以必须要保证该共享变量的原子性(要么全部执行成功,要么全部不执行
// code:共享变量值异常
public class Main {
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) value++;
System.out.println("线程A结束");
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) value++;
System.out.println("线程B结束");
});
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println(value);
}
}
通过synchronized同步代码块,必须要同一锁,也就是同一对象
// code:悲观锁
public class Main {
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (Main.class) {
value++;
}
}
System.out.println("线程A结束");
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (Main.class) {
value++;
}
}
System.out.println("线程B结束");
});
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println(value);
}
}
// code:不同锁,值异常
public class Main {
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
Main main1 = new Main();
Main main2 = new Main();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (main1) {
value++;
}
}
System.out.println("线程A结束");
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (main2) {
value++;
}
}
System.out.println("线程B结束");
});
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println(value);
}
}
死锁的情况
public class Main {
public static void main(String[] args) throws InterruptedException {
Object o1 = new Object();
Object o2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (o1) {
try {
Thread.sleep(1000);
synchronized (o2) {
System.out.println("线程A");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() -> {
synchronized (o2) {
try {
Thread.sleep(1000);
synchronized (o1) {
System.out.println("线程B");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
wait、notify、notifyAll方法执行,
public class Main {
public static void main(String[] args) throws InterruptedException {
Object o1 = new Object();
Thread t1 = new Thread(() -> {
synchronized (o1) { //对象作为锁
try {
System.out.println("A开始等待");
o1.wait(); //进入等待状态并释放锁
System.out.println("A等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() -> {
synchronized (o1) {
System.out.println("B被唤醒");
o1.notify(); //唤醒处于等待状态的线程
o1.notifyAll(); //notifyAll是唤醒全部
for (int i = 0; i < 50; i++) {
System.out.println(i);
}
//执行完后,释放锁,等待状态的线程拿到锁才能执行
}
});
t1.start();
Thread.sleep(1000);
t2.start();
}
}
// result
A开始等待
B开始执行
0
1
......
48
49
A等待结束
ThreadLocal
线程自己单独空间存放变量值
// code:其他线程无法获取自己线程空间的变量
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadLocal<String> local = new ThreadLocal<>();
Thread t1 = new Thread(() -> {
local.set("xiao");
System.out.println("已给值");
System.out.println(local.get());
});
Thread t2 = new Thread(() -> {
System.out.println(local.get());
});
t1.start();
Thread.sleep(3000);
t2.start();
}
}
// result
已给值
xiao
null
子线程无法获取父线程的ThreadLocal值?
// code:InheritableThreadLocal可以让子线程拿到父线程的变量
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadLocal<String> local = new InheritableThreadLocal<>();
Thread t1 = new Thread(() -> {
local.set("xiao");
new Thread(()->{
System.out.println(local.get());
}).start();
});
t1.start();
}
}
定时器
自定义
public class Main {
public static void main(String[] args) throws InterruptedException {
//new TimeTask(() -> System.out.println("定时任务"), 3000).start();
new TimeLoopTask(() -> System.out.println("定时任务"), 1000).start();
}
static class TimeTask {
Runnable task;
long time;
public TimeTask(Runnable task, long time) {
this.task = task;
this.time = time;
}
public void start() {
new Thread(() -> {
try {
Thread.sleep(time);
task.run(); //休眠后再运行
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
static class TimeLoopTask {
Runnable task;
long looptime;
public TimeLoopTask(Runnable task, long looptime) {
this.task = task;
this.looptime = looptime;
}
public void start() {
new Thread(() -> {
try {
while (true) {
Thread.sleep(looptime);
task.run(); //休眠后再运行
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
java自带Timer类进行定时任务调度
public class Main {
public static void main(String[] args) throws InterruptedException {
Timer timer = new Timer(); //创建定时器对象
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
timer.cancel(); //结束进程
}
}, 1000); //延时执行任务
}
}
守护线程
// code:父线程是守护线程,子线程也会跟着结束
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
Thread it = new Thread(() -> { //子线程
while (true) {
try {
System.out.println("正常运行");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
it.start();
});
t.setDaemon(true); //设置为守护线程
t.start();
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
}
}
}
集合并行方法
public class Main {
public static void main(String[] args) throws InterruptedException {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 5, 8, 3, 4));
list
.parallelStream() //并行流
//forEachOrdered 单线程,是有序的
.forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
}
}
生产者消费者
public class Main {
private static final List<Object> list = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
Thread c1 = new Thread(Main::add);
c1.setName("生产A");
Thread c2 = new Thread(Main::add);
c2.setName("生产B");
c1.start();
c2.start();
Thread s1 = new Thread(Main::take);
s1.setName("消费A");
Thread s2 = new Thread(Main::take);
s2.setName("消费B");
Thread s3 = new Thread(Main::take);
s3.setName("消费C");
s1.start();
s2.start();
s3.start();
}
private static void add() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (list) {
list.add(new Object());
System.out.println(new Date() + Thread.currentThread().getName() + "已生产");
list.notify();
}
}
}
private static void take() {
while (true) {
try {
synchronized (list) {
while (list.isEmpty()) { //循环判断是否为空,空的情况就不能去取
list.wait();
}
}
Thread.sleep(4000);
System.out.println(new Date() + Thread.currentThread().getName() + "已消费");
list.remove(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}