【Java多线程】Java多线程(1)
前言:
本文内容:多线程概述、线程进程多线程、继承Thread类、网图下载、实现Runnable接口、初识并发问题、龟兔赛跑
推荐免费Java多线程讲解视频:【狂神说Java】多线程详解_哔哩哔哩_bilibili
多线程概述
讲解大纲:
- 线程简介
- 线程实现
- 线程状态
- 线程同步
- 线程通信问题
- 高级主题
线程、进程、多线程
多任务:
- 边吃饭边玩手机等,现实中太多这样同时做多件事情的例子了,看起来是多个人物都在做,其实本质上我们的大脑在同一时间依旧只做了一件事情。
多线程:
- 原来是一条路,慢慢因为车太多了,道路阻塞,效率极低。
- 为了提高使用的效率,能够充分利用道路,于是加了多个车道。
- 网络游戏,编程等等
普通方法调用和多线程:
程序、进程、线程:
Process与Thread:
- 说起进程,就不得不说程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
- 而进程则是执行程序的一次执行过程,它是一个动态概念。是系统资源分配的单位。
- 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位。
- 注意:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
本章核心概念:
- 线程就是独立的执行路径;
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()
称之为主线程,为系统的入口,用于执行整个程序;- 在一个进程中,如果开辟了多个线程,现成的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的;
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发通知;
- 线程会带来额外的开销,如CPU调度事件,并发通知开销;
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。
继承Thread类
线程三种创建方式:
Thread类:(多查看JDK帮助文档)
-
自定义线程继承Thread类
-
重写
run()
方法,编写线程执行体 -
new当前类,直接调用
start()
方法启动线程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package com.jokerdig.demo1;
/**
* @author Joker大雄
* @data 2021/8/20 - 18:32
**/
//创建线程方式
public class TestThread1 extends Thread{
public void run(){
//run方法
for (int i = 0; i < 20; i++) {
System.out.println("在看代码"+i);
}
}
public static void main(String[] args) {
//main方法
TestThread1 testThread1 = new TestThread1();
//调用start()方法i
testThread1.start();
for (int i = 0; i < 200; i++) {
System.out.println("学习多线程"+i);
}
}
}
总结:
- 注意,线程开启不一定立即执行,由CPU调度执行。
网图下载
下载图片:
1 | package com.jokerdig.demo1; |
实现Runnable接口
-
定义MyRunnable类实现Runnable接口
-
重写
run()
方法,编写线程执行体 -
创建线程对象,调用
start()
方法启动线程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32package com.jokerdig.demo1;
/**
* @author Joker大雄
* @data 2021/8/20 - 19:04
**/
//创建线程方式2:实现runnable接口,重写run方法,执行线程丢入runnable接口实现类,调用start方法
public class TestThread3 implements Runnable{
//重写run方法
public void run() {
//run方法
for (int i = 0; i < 20; i++) {
System.out.println("在看代码"+i);
}
}
public static void main(String[] args) {
//main方法
TestThread3 testThread3 = new TestThread3();
//创建线程对象,来开启start
Thread thread = new Thread(testThread3);
//调用start()方法i
thread.start();
for (int i = 0; i < 200; i++) {
System.out.println("学习多线程"+i);
}
}
}
小结:
- 继承Thread类
- 子类继承Thread类具备多线程额能力;
- 启动线程:子类对象.
start()
; - 不建议使用:避免OOP单继承局限性;
- 实现Runnable接口
- 实现接口Runnable具有多线程能力;
- 启动线程:传入目标对象+Thread对象.
start()
; - 推荐使用:避免单继承局限性,灵活方便,便于同一个对象被多个线程使用;
初识并发问题
-
买火车票;
-
发现问题:多个线程操作同一个资源,线程不安全,数据紊乱(并发问题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39package com.jokerdig.demo1;
/**
* @author Joker大雄
* @data 2021/8/20 - 19:29
**/
//多个线程同时操作一个独享
//买火车票例子
//发现问题:多个线程操作同一个资源,线程不安全,数据紊乱(并发问题)
public class TestThread4 implements Runnable{
//票数
private int ticketNums = 10;
public void run() {
while(true){
if(ticketNums<=0){
//没有票,退出
break;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 拿到了第"+ticketNums+" 票");
ticketNums--;//售出票后减少
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"张三").start();
new Thread(ticket,"李四").start();
}
}
龟兔赛跑
龟兔赛跑-Race:
- 首先来个赛道距离,然后要离终点越来越近;
- 判断比赛是否结束;
- 打印出胜利者;
- 龟兔赛跑开始;
- 故事中是乌龟赢,兔子需要睡觉,我们来模拟兔子睡觉;
- 终于,乌龟赢得比赛;
代码:
1 | package com.jokerdig.demo1; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hey,Joker!
评论
ValineTwikoo