多线程1
1.了解多线程
1.1 概念
- 进程是系统分配资源的最小单位,线程是系统调度的最小单位。
- 一个进程内的线程之间是可以共享资源的。
- 每个进程至少有一个线程存在,即主线程。
- 线程创建比进程创建更轻量级。(线程是轻量级进程)
Java自己的线程:
JVM中的线程不一定就是OS中的线程,但表现出来的特性是相似的。
对于Java程序员,不需要关心操作系统中的线程。
1.2 观察线程
1.2.1 示例
public class ThreadDemo1 {
private static class MyThread extends Thread {
@Override
public void run() {
while (true) {
System.out.println("我在 method2 中打印");
// 进程会暂停运行 1 秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static void method2() {
Thread thread = new MyThread();
thread.start();
}
public static void main(String[] args) throws InterruptedException {
/*
//method1死循环
method1();
*/
// 两个死循环可以同时开始执行,没有一个卡住另一个的情况
method2();
while (true) {
System.out.println("我在 main 中打印");
// 进程会暂停运行 1 秒
Thread.sleep(1000);
}
}
private static void method1() throws InterruptedException {
while (true) {
System.out.println("我在 method1 中打印");
// 进程会暂停运行 1 秒
Thread.sleep(1000);
}
}
}
1.调用method1(),死循环
2.调用method2(),两个死循环可以同时开始执行,没有一个卡住另一个的情况
1.2.2 使用jconsole观察线程
前提:运行程序
方法一:直接双击打开
方法二:在IDEA的jconsole命令
1.打开Terminal
2.运行jconsole命令
3.观察线程
1.2.3 线程阻塞观察
-
mian线程处于阻塞状态
-
子线程处于阻塞状态
-
main线程和子线程均处于阻塞状态
-
线程执行顺序
1.3 多线程的优势
一、什么时候使用多线程?
(1)需要同时执行多个任务,当每个任务量都比较大时,可以使用多线程提高效率。
(2)当前线程执行阻塞式代码时,需要同时执行其他代码,可以使用多线程达到不阻塞执行其他代码的目的。
二、使用多线程的优势?
(1) 某些场景下,建模简单(代码好写)。
(2) 某些场景下,增加运行速度。
public class ThreadDemo2 {
private static final long COUNT = 10_0000_0000;
public static void main(String[] args) throws InterruptedException {
serial(); // 串行
concurrent(); // 并发
}
private static class CalcThread extends Thread {
@Override
public void run() {
int n = 0;
for (long i = 0; i < COUNT; i++) {
n++;
}
}
}
private static void concurrent() throws InterruptedException {
long begin = System.nanoTime();
Thread thread1 = new CalcThread();
thread1.start();
Thread thread2 = new CalcThread();
thread2.start();
int a = 0;
for (long i = 0; i < COUNT; i++) {
a++;
}
thread1.join();
thread2.join();
long end = System.nanoTime();
double s = (end - begin) * 1.0 / 1000 / 1000 / 1000;
System.out.printf("并发模式: 耗时: %.4f%n", s);
}
private static void serial() {
long begin = System.nanoTime();
int a = 0;
for (long i = 0; i < COUNT; i++) {
a++;
}
int b = 0;
for (long i = 0; i < COUNT; i++) {
b++;
}
int c = 0;
for (long i = 0; i < COUNT; i++) {
c++;
}
long end = System.nanoTime();
double s = (end - begin) * 1.0 / 1000 / 1000 / 1000;
System.out.printf("串行模式: 耗时: %.4f%n", s);
}
}
运行结果:
注意:多线程不一定都比单线程快。
eg:数据量是100000时,单线程更快一点,运行结果如下
三、多线程的效率问题
(1)运行单个线程的任务量。
任务量越小,相对线程创建及申请系统调度的时间来说,不是很划算。
(2)运行的线程数量。
线程数与系统资源(包括CPU核数、内存大小等等)相关,在当前系统可用资源的条件下,多线程数量有一定阈值。如果单个任务量比较多,使用多线程提高效率(通过增加线程数提高效率时,达到阈值后,效率下降)。
1.4 创建线程
Thread类作用:线程的描述类。
每一个线程都有一个Thread对象与之一一关联。
1.4.1 创建线程_继承Thread类
可以通过继承 Thread 来创建一个线程类,该方法的好处是 this 代表的就是当前线程,不需要通过 Thread.currentThread()
来获取当前线程的引用。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("这里是线程运行的代码");
}
}
MyThread t = new MyThread();
t.start(); // 线程开始运行
1.4.2 创建线程_实现 Runnable 接口
通过实现 Runnable 接口,并且调用 Thread 的构造方法时将 Runnable 对象作为 target 参数传入来创建线程对象。
该方法的好处是可以规避类的单继承的限制;但需要通过 Thread.currentThread()
来获取当前线程的引用。
class MyRunnable implements Runnable { // Runnable 为线程的任务描述
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "这里是线程运行的代码");
}
}
Thread t = new Thread(new MyRunnable());
t.start(); // 线程开始运行
2.Thread 类及常见方法
https://editor.csdn.net/md/?articleId=104105959
3.线程的六种状态和状态转移图
https://editor.csdn.net/md/?articleId=102922752#31__1
4.线程安不安全?
https://editor.csdn.net/md/?articleId=104126766
5.java中保证线程安全的机制
https://blog.csdn.net/qq_43361209/article/details/103000818
6.多线程案例
1.阻塞式队列—生产者消费者模式
https://blog.csdn.net/qq_43361209/article/details/104155767
2.单例模式
https://blog.csdn.net/qq_43361209/article/details/104155700
3.定时器
https://blog.csdn.net/qq_43361209/article/details/104158322
4.线程池
https://blog.csdn.net/qq_43361209/article/details/104160774