Java学习路程之多线程和匿名内部类

一.线程
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中的方法

猜你喜欢

转载自blog.csdn.net/l710820742/article/details/82764274