大纲
-------------------------学前必读----------------------------------
学习不能快速成功,但一定可以快速入门
整体课程思路:
1.实践为主,理论化偏少
2.课程笔记有完整的案例和代码,(为了学习效率)再开始之前我会简单粗暴的介绍知识点案例思路,
有基础的同学听了之后可以直接结合笔记写代码,
如果没听懂再向下看视频,我会手把手编写代码和演示测试结果;
3.重要提示,学编程和学游泳一样,多实践学习效率才高,理解才透彻;
4.编码功底差的建议每个案例代码写三遍,至于为什么…<<卖油翁>>…老祖宗的智慧
-------------------------------------------------------------------------
1.线程
1.1.什么是线程
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。(来自百度百科)
一个进程可以有很多线程,每条线程并行执行不同的任务。
1.2.多线程hello word
需求:模拟在计算上一边听歌一边打游戏
三种实现方案如下:
/**
* @author xiaomingstu
* @date 2020-06-11 21:30
* @description 需求分析:
* 1.模拟一边打游戏一边听音乐,在控制台打印输出模拟
* 2.把两个业务封装成独立的线程,实现接口Runnable或继承Thread,通过看源码你会发现Thread类实现了接口Runnable,使用本质上这两种方法时一样的。
* 3.Thread类提供两个方法,线程主题方法run,启动线程方法start
*/
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException{
//继承Thread
System.out.println("-----------test start----------");
MusicThread musicThread = new MusicThread();
GameThread gameThread = new GameThread();
Thread musicT1 = new Thread(musicThread);
Thread gameT1 = new Thread(gameThread);
musicT1.start();
gameT1.start();
Thread.sleep(5*1000);
System.out.println("-----------test end----------");
//实现Runnable
System.out.println("-----------test start2----------");
MusicRunnable musicRunnable = new MusicRunnable();
GameRunnable gameRunnable = new GameRunnable();
Thread musicT2 = new Thread(musicRunnable);
Thread gameT2 = new Thread(gameRunnable);
musicT2.start();
gameT2.start();
Thread.sleep(5*1000);
System.out.println("-----------test end2----------");
//简写,这种写法一般我们在做模拟测试的使用,在正式代码中建议不使用,可读性较差
System.out.println("-----------test start3----------");
Thread musicThread3 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("===========海阔天空===========" + i);
}
});
Thread gameThread3 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("==========我们一起吃鸡=========" + i);
}
});
musicThread3.start();
gameThread3.start();
Thread.sleep(5 * 1000);
System.out.println("-----------test end3----------");
}
}
/**
* 打游戏
*/
class GameRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("==========我们一起吃鸡=========" + i);
}
}
}
/**
* 听音乐
*/
class MusicRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("==========海阔天空=========" + i);
}
}
}
/**
* 打游戏
*/
class GameThread extends Thread{
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("===========我们一起农药===========" + i);
}
}
}
/**
* 听音乐
*/
class MusicThread extends Thread{
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("===========海阔天空===========" + i);
}
}
}
总结
启动线程两种方式:
1.通过继承Thread类
2.实现Runnable接口
使用哪种方式更好?
区别:
一个类如果继承了其他类,就无法在继承Thread类,在Java中,一个类只能继承一个类,而一个类如果实现了一个接口,还可以实现其他接口,接口是可以多实现的,所以说Runable的扩展性更强,但是继承的方式更简单,个人建议一般情况下使用Thread;
实现接口Runnable或继承Thread,通过看源码你会发现Thread类实现了接口Runnable,使用本质上这两种方法是一样的
启动线程流程:
创建启动线程的方式一:继承Thread类
1.将业务方法封装成线程对象,自定义类t extends Thread类;
2.覆写run方法: 覆写第一步中的run方法;
3.创建自定义对象t
4.启动线程 t.start();
创建启动线程方式二:实现Runnable接口
1.将业务方法封装成线程对象,自定义类t implements Runnable接口;
2.实现第一步中的run方法
3.创建自定义对象t
4.启动线程 new Thread(t).start();
1.3.对主线程与创建线程执行顺序的理解
问题:
直接写一个简单的HelloWorld 程序,有没有线程?
==>有一个主线程,在垃圾回收的时候,有gc 线程。
/**
* @author xiaomingstu
* @date 2020-06-11 21:49
* 问题:
* 直接写一个简单的HelloWorld 程序,有没有线程?
* ==>有一个主线程,在垃圾回收的时候,有gc 线程。
* 结论:一旦线程启动起来之后就是独立的,和创建环境没有关系;
* 启动线程不能直接调用run方法,必须调用start方法;
*/
public class ThreadDemo1 {
public static void main(String[] args) throws InterruptedException{
/**
* 如果把创建线程放在循环语句的 下 面,会交替出现吗
* ==>否,因为主线程执行完成后才会启动hello线程
*/
System.out.println("-------------test start--------------");
//执行主线程
for (int i = 0; i < 100; i++) {
System.out.println("----------------test1------------");
}
// 启动hello线程
new HelloThread().start();
Thread.sleep(5 * 1000);
System.out.println("-------------test end--------------");
/**
* 如果把创建线程放在循环语句的上面,会交替出现吗
* ==>可能会,可能不会,可能出现for循环完之后,线程还没有启动完;
*/
System.out.println("-------------test start2--------------");
// 启动hello线程
new HelloThread().start();
//执行主线程
for (int i = 0; i < 100; i++) {
System.out.println("----------------test2------------");
}
Thread.sleep(5 * 1000);
System.out.println("-------------test end2--------------");
}
}
class HelloThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("----------------HelloThread----------------");
}
}
}
结论:一旦线程启动起来之后就是独立的,和创建环境没有关系;
启动线程不能直接调用run方法,必须调用start方法;