今日内容
零、 复习昨日
一、作业
二、进程与线程
三、创建线程
四、线程的API
一、复习
IO流的分类
- 方向: 输入,输出
- 类型: 字节(XxxStream),字符(XxxReader,XxxWriter)
- 字节输入流类名: FileInputStream
- 字节输出流类名: FileOutputStream
- 字符输入流类名: FileReader
- 字符输出流类名: FileWriter
利用try-catch-finally代码写法是重点
ArrayList和LinkedList的异同点
- ArrayList 底层是数组,容量10,装满扩容1.5倍
- LinkedList 底层是链表
- 相同点: 都是存储多个元素,有序,且允许重复元素
- 不同点: 底层实现原理不一样,AL查询更新快 LL插入删除较快
解析字符串日期为日期对象的方法签名
Date date = sdf.parse(“2020-01-01”);
Date parse(String s)解析字符串数字为int数字的方法签名
static int parseInt(String s)int n = Integer.parseInt(“1”);
String,Date,try-catch-finally
ArrayList,HashMap
认真,慢一点,写一遍(用法,解释,代码)到本上
二、进程与线程[了解]
进程:
一个
进程就是一个应用程序,进程包含线程
一个进程至少包含一个线程,大部分都是有多条线程在执行任务(多线程),每个独立运行的程序都对应一个进程。进程是资源分配的最小单位
,占用独立的内存空间和系统资源
- qq,微信,迅雷
线程:
线程是进程内部的一个执行任务
进程内多个线程是共享进程资源,
线程是资源调度的最小单位(CPU调度和分派的基本单位)
- qq在聊天,视频,传输文件
- 迅雷同时下载多个资源
Java程序是否是多线程的吗?
答: 是! main线程,gc垃圾回收线程
为什么需要多线程?
- 并行处理任务,提高效率
Java程序本身,是否多线程?
- 是,至少有一个线程是"main"线程
- 还有一个线程是没有直接看到,但是一直在"背后"运行,垃圾回收线程(GC)
三、创建线程[重点]
Thread
创建线程的方式有很多
继承Thread
实现Runnable接口
- 使用Callable 和FutureTask来完成
- 使用线程池获得线程
3.1 继承Thread
步骤
- 自定义类
- 继承Thread
- 重写
run
方法- 创建子类对象
调用start方法启动线程
[特别强调,开启新线程的方法是start
]
start方法内部执行时会调用run方法执行
public class MyThread extends Thread{// 重写方法,方法内部,就是该线程执行的任务@Overridepublic void run() {for (int i = 1; i < 101; i++) {System.out.println("MyThread --> "+i );}}
}
public class TestThread{public static void main(String[] args) {// 创建一个线程MyThread myThread = new MyThread( );// 启动线程,不是调用run()方法!!!!// 调用start方法开启新线程myThread.start();// ==============main线程执行====================for (int i = 1; i < 101; i++) {System.out.println("main --> " + i );}// 自定义线程和主线程同时执行,并且出现资源争抢情况}
}
3.2 实现Runnable接口
步骤
- 自定义类
- 实现Runnable接口
- 重写run方法
- 创建子实现类对象
把子实现类对象当构造方法的方法参数来创建Thread对象
- 由thread调用start方法开启线程
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 1; i < 101; i++) {System.out.println("MyRunnable --> " + i);}}
}
public static void main(String[] args) {// 4 创建实现类对象MyRunnable myRunnable = new MyRunnable( );// 5 把对象当构造方法参数,创建Thread对象Thread thread = new Thread(myRunnable);// 6 开启线程thread.start();}
匿名内部类的形式创建线程
// ============= 匿名内部类完成实现Runnable接口 ============
public class Demo4Annoy {public static void main(String[] args) {Runnable runnable = new Runnable( ) {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("匿名内部类 --> " + i);}}};Thread thread = new Thread(runnable);thread.start();// new Thread( new Runnable() {// @Override// public void run() {// for (int i = 0; i < 100; i++) {// System.out.println("匿名内部类 --> " + i );// }// }// }).start();for (int i = 0; i < 100; i++) {System.out.println("main --> " + i);}}
}
3.3 区别
继承Thread开启线程和实现Runnable接口开启线程有什么区别?
- 一个继承,一个实现
- 继承Thread后,直接创建对象即可调用start开启线程
- 实现Runnable接口的子类,还需要再创建Thread类对象才可以调用strat开启线程
从使用便捷度来说,继承Thread开启线程会方便一点…因为创建完线程对象可以直接调用start开启线程
继承Thread类就限制了该类不能再继承别的类,因为类只能单继承,而实现接口的同时可以继承别的类,并且还允许多继承,
所以推荐使用接口来实现多线程.
3.4 其他创建线程方式
package com.qf.thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;public class Callable01 {public static void main(String[] args) throws InterruptedException, ExecutionException {// FutureTask对象用于接收线程返回值, FutureTask 实现了RunnableFuture接口// public class FutureTask<V> implements RunnableFuture<V> {}// RunnableFuture接口继承了Runnable和Future接口,后面用到的get方法来自Future接口// public interface RunnableFuture<V> extends Runnable, Future<V>{}FutureTask<String> futureTask = new FutureTask<String>(new MyCallable());Thread thread = new Thread(futureTask);thread.start();System.out.println("-----------------");// 该语句阻塞程序的执行,等待线程执行完毕,获取线程返回的数据String result = futureTask.get();System.out.println(result);}
}// 实现Callable接口的类
class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println(Thread.currentThread().getName());Thread.sleep(5000);return "haha";}
}
四、Thread的API[熟悉]
void start() 开启线程
,会自动run方法执行线程任务void run() 执行线程的方法
- run() 方法是start开启线程后,JVM自动调用
- void setName(String name) 给线程设置名字
- 也可以通过构造方法,在创建线程时指定线程名
- String getName() 获得线程的名字
static Thread currentThread()
返回当前正在执行的线程对象- join() 加入线程,等待该线程终止
- join(int milles) 加入线程,最大等待直到毫秒数
- void setDaemon(boolean on) 设置守护线程
static void sleep(long milles) 线程休眠
- 会让当前线程暂停执行,
让出系统资源
,让其他线程执行- 时间到,当前会继续和其他争抢资源执行
- void stop() 结束当前线程,线程死亡(已过式)
- 被废弃的原因是因为这个中断线程太直接太暴力…
线程名字
- String getName()
- void setName()
- Thread(String name)
package com.qf.thread_api;/*** --- 天道酬勤 ---** @author QiuShiju* @desc 关于线程名字操作*/
public class Demo1 {public static void main(String[] args) {new Thread(){@Overridepublic void run() {// 给线程设置名字this.setName("驴车");// 创建线程,默认会分配名字,安装thread-x来命名System.out.println("开启新线程,线程名: " + getName());}}.start();new Thread(){@Overridepublic void run() {this.setName("火车");// 创建线程,默认会分配名字,安装thread-x来命名System.out.println("开启新线程,线程名: " + getName());}}.start();new Thread(){@Overridepublic void run() {this.setName("飞机");// 创建线程,默认会分配名字,安装thread-x来命名System.out.println("开启新线程,线程名: " + getName());}}.start();Thread thread = new Thread(){@Overridepublic void run() {}};System.out.println(thread.getName( ));thread.setName("火箭");System.out.println(thread.getName( ));/*** 还可以通过构造方法,在创建线程时指定线程名*/Thread thread5 = new Thread("子弹头"){@Overridepublic void run() {}};System.out.println("线程5-->" + thread5.getName( ));}
}
获得当前线程对象
- static Thread currentThread()
public static void main(String[] args) {new Thread("火车"){@Overridepublic void run() {Thread t = Thread.currentThread( );System.out.println(t.getName()+",在执行..." );}}.start();/*** 获得当前正在执行的线程对象*/Thread thread = Thread.currentThread( );System.out.println("当前正在执行的线程名字是: "+thread.getName( ));
}
线程加入
- join()
- join(long mill)
public static void main(String[] args) {Thread t1 = new Thread("线程1"){@Overridepublic void run() {for (int i = 1; i < 1001; i++) {System.out.println(getName()+"-->"+i );}}};Thread t2 = new Thread("线程2"){@Overridepublic void run() {for (int i = 1; i < 1001; i++) {System.out.println(getName()+"-->"+i );if (i == 100) {try {// 在当前线程下加入另一个线程// 相当于"插队",直到插入的线程执行完//t1.join();// 让另外一个线程加入指定时间,到时后继续争抢t1.join(10);} catch (InterruptedException e) {e.printStackTrace( );}}}}};t1.start();t2.start();
}
守护线程
void setDaemon(boolean x)
守护线程是指,A线程守护B线程,即B是被保护,B是重要的,当B线程结束时A线程(守护线程)会立即结束
public static void main(String[] args) {Thread hs = new Thread("皇上"){@Overridepublic void run() {for (int i = 1; i < 11; i++) {System.out.println(getName()+"工作"+i+"天" );}}};Thread fz = new Thread("妃子"){@Overridepublic void run() {for (int i = 1; i < 101; i++) {System.out.println(getName()+"工作"+i+"天" );}}};/*** 不需要设置被守护,只需要设置守护线程,其他默认就是被守护线程* 开启线程前设置*/fz.setDaemon(true);hs.start();fz.start();
}
线程休眠
- sleep(long millis)
- 会让当前线程陷入等待状态(阻塞)状态,让其资源让其他线程执行
public static void main(String[] args) throws InterruptedException {for (int i = 10; i > 0; i--) {System.out.println("倒计时 --> " + i );Thread.sleep(1000);}System.out.println("发射!" );
}private static void show() {Thread t1 = new Thread("线程1"){@Overridepublic void run() {for (int i = 1; i < 101; i++) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace( );}System.out.println(getName()+"-->"+i );}}};Thread t2 = new Thread("线程2"){@Overridepublic void run() {for (int i = 1; i < 101; i++) {System.out.println(getName()+"-->"+i );}}};t1.start();t2.start();
}
结束线程
- void stop() 结束当前线程
- void interrupt() 设置线程中断状态为以中断
- boolean isInterrupt() 测试返回线程是否中断
public static void main(String[] args) {new Thread("线程2"){@Overridepublic void run() {for (int i = 1; i < 101; i++) {if (i == 15){//this.stop(); // 直接结束线程this.interrupt();// 给线程设置一个中断状态,不会真的中断线程// 结束不结束取决于线程本身执行情况}System.out.println("是否中断? "+this.isInterrupted() );System.out.println(getName()+"-->"+i );}}}.start();
}
五、线程状态[面试]
线程的几种状态:
- 创建/新建/初始
- new 完线程对象
- 就绪
- 调用start
- 等待/阻塞
- join()或者sleep()
- 运行
- 执行run()方法
- 死亡/销毁/终止
- run方法执行完,或者调用stop()或者interrupt()中断等
清楚状态之间的转换