一.线程
1.线程分类:单线程和多线程
进程:一个正在运行的程序就是一个进程(一个进程中可有一个或多个线程)
单线程:就是进程只有一个线程
好处:代码安全
弊端:执行效率低
多线程:
好处:提高任务的执行效率,但是线程本身也会耗费系统资源,创建线程要把握一个度
2.分时调度:CPU(单核单线程)同一时间只能执行一个任务,同时执行多个任务时,CPU就会为这几个任务开辟独立的执行路径(运行功能的代码)CPU会在这几个任务之间进行快速切换
main函数调用:
1).JVM调用main函数
2).CPU为main函数开辟独立的执行路径
3).这个路径中就执行main中的代码
注意:程序只有一个主线程,其他的都是子线程并且这个主线程名字就叫main
创建多线程方法一:
两种方式的优劣:
继承方式创建:
1.增加类与类之间的耦合度
2.Java中类只能单继承
实现接口创建:
1.接口可以多实现 灵活
2.将线程中实现的方法分离出来
一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法
run和start方法的区别:
调用run方法是调用了成员方法
调用start方法,开启了多线程(创建独立的执行路径),线程中的任务是调用了run方法
public class Day22 {
public static void main(String[] args) {
//创建子线程//创建子线程
SonThread sonThread = new SonThread();
sonThread.start();//开启线程,执行的任务就是重写的run方法
}
}
class SonThread extends Thread{
//重写run方法
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(i + "哈哈");
}
}
}
多线程创建方法二:
runnable接口创建
public class Day22 {
public static void main(String[] args) {
//创建接口的实现类//创建接口的实现类
SubThread subThread = new SubThread();
//创建线程类对象
Thread thread = new Thread(subThread);
thread.start();
}
}
class SubThread implements Runnable{
//重写run方法
@Override
public void run() {
System.out.println("实现接口类方法");
}
}
3.获取设置线程的名字
public class Day22 {
public static void main(String[] args) {
//设置子线程默认名字(通过构造方法)
NameThread nameThread1 = new NameThread("啦");
nameThread1.start();//开启线程
NameThread nameThread2 = new NameThread();
//set方法设置线程默认名字
nameThread2.setName("xi");
nameThread2.start();
//打印主线程名字
// 获取当前正在执行的线程对象,放在哪个线程中就表示哪个线程对象
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName());
}
}
class NameThread extends Thread{
//构造方法
public NameThread() {
}
//构造方法设置名字
public NameThread(String name) {
super(name);
}
public void run() {
//获取当前线程的名字
for (int i = 0; i < 20; i++) {
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() +"--"+ i);
}
}
}
创建一个线程类,类中有个name属性 并提供 有参无参 set/get方法
class SonThread extends Thread{
private String name;
//构造方法
public SonThread() {
}
public SonThread(String name, String myName) {
super(name);
//给自己类name赋值
this.name = myName;
}
//set/get
//父类中使用final修饰了set/get方法所以子类不能重写,使用不同的方法名来解决
public String getMName() {
return name;
}
public void setMName(String name) {
this.name = name;
}
}
4.多线程在内存中的表现
多线程在内存的表现,也符合在栈区执行先进后出的原则
创建多线程子类对象时,开辟了一个新的栈区,调用开启的方法后这个栈才能运行代码,运行的代码就是run方法中的代码.
public class Day22 {
public static void main(String[] args) {
TestThread tt = new TestThread();
tt.start();//开启线程,调用run方法在新开辟的栈区运行
fnMain();
System.out.println("最后");//在fnMain()方法执行完毕后开始运行
}
public static void fnMain() {
for (int i = 0; i < 20; i++) {
//获取当前名字
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() + "fnMain");
}
}
}
class TestThread extends Thread{
public void run() {
for (int i = 0; i < 20; i++) {
//获取当前名字
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() + "run");
}
fn();//该方法在上面循环结束后才会执行
}
public void fn() {
System.out.println(Thread.currentThread().getName() + "fn");
}
}
二.匿名内部类
1.匿名内部类创建子类或实现类对象
public class Day22 {
public static void main(String[] args) {
//创建了Test类的子类的对象,并且没有类名
//父类的引用接收子类的对象,方法运行看子类
Test test = new Test() {
public void fn() {
System.out.println("我是重写的fn方法");
}
};
test.fn();//输出:我是重写的fn方法
//创建接口的实现类
//new Inter() {}接口的实现类对象
//注意:new后面是类名或接口名,{}里类或接口中的方法
Inter inter = new Inter() {
public void fn() {
System.out.println("我是实现类的fn方法");
}
};
interA.fn();
//匿名内部类直接调用方法
new InterA() {
public void fn() {
System.out.println("我是实现类的fn方法");
}
}.fn();
}
}
class Test{
public void fn() {
System.out.println("我是test中的fn方法");
}
}
interface Inter{
public abstract void fn();
}
利用匿名内部类方式, 给集合中 3个学生对象 按年龄进行排序(使用比较器)
public class Day22 {
public static void main(String[] args) {
//创建比较器内部类
Comparator<Student> comparator = new Comparator<Student>() {
//重写排序规则
public int compare(Student o1, Student o2) {
int num = o1.getAge() - o2.getAge();
return num = num == 0 ? 1 : num;
}
};
TreeMap<Student, String> treeMap = new TreeMap<>(comparator);
treeMap.put(new Student("李四", 18), "江苏");
treeMap.put(new Student("王五", 16), "新疆");
treeMap.put(new Student("张三", 22), "云南");
System.out.println(treeMap);
}
}
2.匿名内部类 创建线程
public class Day22 {
//线程类的子类创建
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("线程子类的run方法");
}
};
thread.start();
//接口类的实现类创建
Runnable runnable = new Runnable() {
public void run() {
System.out.println("接口实现类的对象的run方法");
}
};
Thread thread2 = new Thread(runnable);
//结合写
Thread thread3 = new Thread(new Runnable() {
public void run() {
System.out.println("接口实现类的对象的run方法");
}
});
}
}
3.线程休眠方法
public class Day22 {
public static void main(String[] args) throws InterruptedException {
//休眠线程 单位毫秒 效果:卡住当前的线程
//注意书写的位置决定休眠哪个线程
Thread.sleep(1000);
System.out.println("我是main方法");
TestThread testThread = new TestThread();
Thread thread = new Thread(testThread);
testThread.start();
}
}
class TestThread extends Thread{
public void run() {
for (int i = 0; i < 20; i++) {
//父类中的run方法没有抛出异常,子类中只能自己处理
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}
}
4.线程的6种状态
见图:
线程调用了start方法必须得到CPU的执行资源才会进入运行状态,线程调用start方法得到了CPU的执行权没有得到CPU的执行资源的线程进入阻塞状态,当受阻塞状态的线程得到了CPU的运行资源,就会变为运行状态.
运行时状态–>休眠状态 放弃了CPU的执行权,休眠时间结束,重新获得CPU的执行权
运行状态–>等待状态 放弃了CPU的执行权,等到调用了notify()方法 重新获得CPU的执行权
注意:注意:notify()和wait()方法是Object中的方法