Java 多线程
程序
静态文件 程序 启动以后以 进程
方式在 操作系统驻留
进程 (可以看见)
- 程序运行过程中 在操作系统内存中一个一个的实例。
- 进程之间 独立存储 独立管理的 彼此是隔离的。
- 程序 在 运行过程 中 至少有一个 进程与之对应 取决于 设计方式
- 进程启动 默认 会启动一个 主线程(决定进程的生死 主线程死 进程死 主线程生 进程生)。
总结 :
- 程序 执行进入内存运行,变为一个进程
- 进程间的资源(内存、文件····)是彼此隔离的,其他进程不允许访问(读取和写入)的。
线程 (看不见)
eg :
- 迅雷 多线程下载软件
概念 :
- 线程 是 进程内的一个 “基本任务”,每个线程都有自己的功能, 是 CPU 分配和调度的基本单位
- 一个进程内可以包含多个线程 , 一个线程只能隶属于一个进程
- 进程内至少拥有一个 线程 这个线程叫做 主线程 主线程消亡 进程 结束。
CPU、进程、线程
单核 CPU
时间片(cpu 一段的执行时间 以 纳秒 为单位)
时间片 分配给 某个线程 ----> 某个线程 来执行
这种情况 叫并发执行。
多核
- 一个线程 在同一时间 只能拥有一个 CPU 的时间片
- 而 多个线程 在不同时间 可以 拥有不同 CPU 的时间片
这就有了 并行 执行
Java 中的 进程 与 线程
Java 最简单程序的进程 包含 main 主线程 和 垃圾收集线程(没有关注你呢)
线程创建的三种方式
Thread (不推荐使用 Java 对 继承不友好)
package nuc.zm.MoreThread.create_thread;
import nuc.zm.io.ObjectIOTest.Object;
/**
* demo1
* @description 创建线程的方式 1
* @author zm
* @date 2022/10/15
*/
public class Demo1 {
public static void main(String[] args) {
TestThread testThread = new TestThread();
for (int i = 0; i < 10; i++) {
System.out.println("不会出现争夺资源的main" + i);
}
Thread thread = Thread.currentThread();
thread.setName("主线程");
// 让子线程先启动 才会出现 和主线程抢夺资源的情况hh
testThread.setName("子线程");
testThread.start();
for (int i = 0; i < 10; i++) {
System.out.println(thread.getName() + i);
}
}
static class TestThread extends Thread {
/**
* 运行
* 线程对象 争抢资源的任务 必须放在 run 方法中
*/
@Override
public void run() {
super.run();
for (int i = 0; i < 10; i++) {
System.out.println(getName() + " ==== " + i);
}
}
}
}
Runnable (Java编程友好 单无法返回执行后的数据)
package nuc.zm.MoreThread.create_thread;
/**
* 以及接下来
* 实现 Runnable 接口 成为线程类
* @author zm
* @date 2022/10/16
*/
public class Demo2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "====" + i);
}
}
// main 线程 启动器
public static void main(String[] args) {
Demo2 demo2 = new Demo2();
Thread thread = new Thread(demo2);
thread.setName("子线程~~");
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "========" + i);
}
}
}
Callable (涉及到线程池 且线程方法具有返回值 但编程显复杂)
package nuc.zm.MoreThread.create_thread;
import java.util.Random;
import java.util.concurrent.*;
/**
* 可调用测试
*
* @author zm
* @date 2022/11/06
*/
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
}
static class ThreadTest implements Callable<Integer> {
private String name;
@Override
public Integer call() throws Exception {
int speed = new Random().nextInt(10);
int result = 0;
for (int i = 1; i < 10; i++) {
Thread.sleep(1000);
result = i * speed;
System.out.println("第 " + i + " 秒 " + this.name + " 已经跑到 " + result + " 米 " + " 速度 " + speed + " 米/秒 ");
}
return result;
}
public void start() throws ExecutionException, InterruptedException {
// 线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
ThreadTest threadTest = new ThreadTest();
threadTest.name = "参赛者A";
ThreadTest threadTest1 = new ThreadTest();
threadTest1.name = "参赛者B";
ThreadTest threadTest2 = new ThreadTest();
threadTest2.name = "参赛者C";
Future<Integer> submit = executorService.submit(threadTest);
Future<Integer> submit1 = executorService.submit(threadTest1);
Future<Integer> submit2 = executorService.submit(threadTest2);
executorService.shutdown();
System.out.println(threadTest.name + "跑了" + submit.get() + "米");
System.out.println(threadTest1.name + "跑了" + submit1.get() + "米");
System.out.println(threadTest2.name + "跑了" + submit2.get() + "米");
}
}
}
package nuc.zm.MoreThread.create_thread;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* demo3
* 实现 callable 接口
* @author zm
* @date 2022/10/16
*/
public class Demo3 implements Callable<Double> {
/**
* 调用
* 抛 子类 异常
* @return {@link Double}
*/
@Override
public Double call() {
return (double) new Random().nextInt(10);
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Demo3 demo3 = new Demo3();
FutureTask<Double> futureTask = new FutureTask<>(demo3);
Thread thread = new Thread(futureTask);
thread.start();
Object o = futureTask.get();
System.out.println(o);
}
}
线程 同步问题
现实案例 : 抛绣球案例 很多人争抢一个绣球(资源)
synchronized(同步锁)
作用 : 利用一个特定的对象
设置一个锁 , 在 多线程 并发访问的时候,同时只允许一个线程 获得这个锁,并执行特定代码。
执行后 会释放锁
, 继续和其他线程争抢资源。
所有线程都访问 同一个打印方法 就会出现 线程安全问题
package nuc.zm.MoreThread;
/**
* 同步采样
* 演示 同步锁
* @author zm
* @date 2022/11/06
*/
public class SyncSample {
static class Printer {
public void print() {
try {
Thread.sleep(500);
System.out.print("你");
Thread.sleep(500);
System.out.print("好");
Thread.sleep(500);
System.out.print("世");
Thread.sleep(500);
System.out.print("界");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void start() {
Printer printer = new Printer();
for (int i = 0; i < 10; i++) {
PrintTask printTask = new PrintTask();
printTask.printer = printer;
Thread thread = new Thread(printTask);
thread.start();
}
}
static class PrintTask implements Runnable {
private Printer printer;
@Override
public void run() {
printer.print();
}
}
public static void main(String[] args) {
new SyncSample().start();
}
}
解决 加锁
synchronized 代码块 – 任意对象
synchronized 方法 – this 当前对象
synchronized 静态方法 – 该类的字节码对象
package nuc.zm.MoreThread;
import java.util.concurrent.locks.Lock;
/**
* 同步采样
* 演示 同步锁
* @author zm
* @date 2022/11/06
*/
public class SyncSample {
static class Printer {
public void print() {
synchronized ("DADADADASDADAADADAD") {
try {
Thread.sleep(500);
System.out.print("你");
Thread.sleep(500);
System.out.print("好");
Thread.sleep(500);
System.out.print("世");
Thread.sleep(500);
System.out.print("界");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void print1() {
try {
Thread.sleep(500);
System.out.print("你");
Thread.sleep(500);
System.out.print("好");
Thread.sleep(500);
System.out.print("世");
Thread.sleep(500);
System.out.print("界");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void print2() {
try {
Thread.sleep(500);
System.out.print("你");
Thread.sleep(500);
System.out.print("好");
Thread.sleep(500);
System.out.print("世");
Thread.sleep(500);
System.out.print("界");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void start() {
Printer printer = new Printer();
for (int i = 0; i < 10; i++) {
PrintTask printTask = new PrintTask();
printTask.printer = printer;
Thread thread = new Thread(printTask);
thread.start();
}
}
static class PrintTask implements Runnable {
private Printer printer;
@Override
public void run() {
printer.print();
// printer.print1();
// Printer.print2();
}
}
public static void main(String[] args) {
new SyncSample().start();
}
}
线程安全
- 在 拥有 多条线程 并行执行的程序中,线程安全的代码 会通过同步机制保证各个线程可以正常 且正确的执行,不会出现数据污染的意外情况。
线程池
JUC 并发工具包 解决 同步 和 互斥问题
- Runnable 新建 线程 , 性能差~~~
- 线程 被频繁创建,相互竞争,严重时可能导致系统资源死机或者内存溢出
- 线程池 ----- 线程复用
- ThreadPool 线程池
- 重用 存在的线程,减少线程对象的创建,消亡的开销
- 线程总数可控,提高资源的利用率
- 提供额外功能,定时执行,定期执行 和 监控。
- 支持的线程池种类
- 工具类 Executors(juc 包下) 创建线程池
- FixedThreadPool - 定长线程池
- CachedThreadPool - 可缓存的线程池
- SingleThreadPool - 单线程池
- ScheduledThreadPool - 调度线程池