java之线程创建的两种方式,六种状态和匿名内部类创建子类或实现类对象
程序员文章站
2024-02-29 21:17:16
...
一.匿名内部类创建子类或实现类对象
new Test(){}
相当于创建了Test类的子类对象
并且没有类名
创建接口实现类
new 接口名() {};接口实现类的对象
注意 : new 后边是类或者接口名
大括号内是类或者接口中的方法
public class Kll {
public static void main(String[] args) {
Test test = new Test() {
@Override
public void fun() {
System.out.println("重写fun方法");
}
};
test.fun();
// 创建接口实现类
// new InterA() {};接口实现类的对象
// 注意 : new 后边是类或者接口名
// 大括号内是类或者接口中的方法
InterA a = new InterA() {
@Override
public void fun() {
System.out.println("接口实现类方法");
}
};
a.fun();
// 匿名内部类直接调用方法
new InterA() {
@Override
public void fun() {
System.out.println("哈哈哈哈哈");
}
}.fun();;
}
}
class Test{
public void fun() {
System.out.println("Test类中的fun方法");
}
}
interface InterA{
public abstract void fun();
}
二.多线程
标准单线程程序
-
好处:代码安全
-
弊端:执行效率低
多线程 -
进程:一个正在运行的程序就是一个进程
-
一个进程可以有一个或多个线程
-
线程:执行的任务
-
分时调度:
- CPU同一时间,只能执行一个任务(CPU单核单线程的原因)
- 现在要同时执行多个任务
- 这时CPU就会为这几个任务开辟相应独立的执行路径
-
(执行路径 运行功能的代码)
- CPU会在多个任务之间进行快速切换
- 抢占资源:抢夺CPU的执行资源,改变任务的优先级
-
多线程好处:
- 提高任务的执行效率(线程本身也会消耗系统资源,创建线程要把握一个度,不是越多越好)
main调用
1.jvm调用main函数1.jvm调用main函数
2.CPU就为main凯比一个独立的执行路径
3.这个路径就执行main中的代码3.这个路径就执行main中的代码
程序只有一个主线程,除了主线程,其他的都叫子线程
这个主线程的名字就叫main
- 线程的名字:
- 主线程:main* 主线程:main
- 子线程:默认 Thread-x(x从0开始)* 子线程:默认 Thread-x(x从0开始)
创建方式:
-
线程创建方式1(继承Thread类,重写run方法)
-
线程创建方式2(使用Runnable接口创建线程)
-
创建放式1:继承方式
- 1.增加类和类的耦合度
- 2.java中,类只能单继承
线程开启方法:start()方法。
执行的任务就是重写run方法。
run方法和start方法的区别:
1.直接调用run方法,就是相当于调用成员方法
2. 直接调用start 开启线程(创建独立执行路径)
3.线程中执行的任务 是run方法中的代码
public class Kll {
public static void main(String[] args) {
// 异常发生在 主线程中
// 创建子线程
SubThread t1 = new SubThread();
// 开启线程
// 执行的任务就是重写run方法
t1.start();
SubThread t2 = new SubThread();
t2.start();
for (int i = 0; i < 50; i++) {
System.out.println("main---" + i);
}
System.out.println("main");
}
}
// 创建子线程类
class SubThread extends Thread{
// 重写run方法
@Override
public void run() {
//System.out.println(10 / 0);
for (int i = 0; i < 50; i++) {
System.out.println("run---" + i);
}
}
}
获取当前线程名字和给线程设置名字:
public class Kll extends Thread{
public static void main(String[] args) {
NameThread n1 = new NameThread("哈哈");
n1.setName("啾啾");
n1.start();
NameThread n2 = new NameThread();
n2.start();
// 获取当前正在执行的线程对象
// 放在哪儿个线程中,就表示哪儿个线程对象
Thread thread = Thread.currentThread();
// 打印主线程名字
System.out.println(thread.getName());
}
}
class NameThread extends Thread{
// 构造方法
public NameThread() {
// TODO Auto-generated constructor stub
}
public NameThread(String name) {
super(name);
}
// 重写run方法
@Override
public void run() {
for (int i = 0; i < 50; i++) {
//获取线程的名字
//System.out.println(this.getName() + "--" + i);
System.out.println(Thread.currentThread().getName() + "++" + i);
}
}
}
父类使用了final修饰set/get方法 ,子类不能重写
可以使用不同的方法名来解决
线程在内存中的表现符合栈内存特点 : 先进后出。
NameTread ta = new NameTread();开辟了一个新栈(相当于CPU独立执行空间)。
ta.start();必须调用开启线程方法,这个栈才能运行代码。
运行的代码就是线程类中run方法。
-
创建方式2:实现方式
- 1.接口可以多实现(灵活)
- 2.将线程要执行的方法从类中分离出来
public class Kll {
public static void main(String[] args) {
// 创建接口实现类对象
RunnableImpl ruImpl = new RunnableImpl();
// 创建线程类对象
Thread t = new Thread(ruImpl);
// 开启线程
t.start();
}
}
class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
- 匿名内部类 创建线程代码:
public class Kll {
public static void main(String[] args) {
// 线程类的子类创建
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("线程子类的run方法");
}
};
t1.start();
// 接口类的实现类创建线程
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("接口实现类");
}
};
// 创建线程对象
Thread t2 = new Thread(r1);
t2.start();
// 合并一起
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("接口实现类和线程对象合并");
}
});
t3.start();
}
}
三.线程的六种状态
-
线程休眠方法(测试时常用)。
- sleep(long time);单位毫秒;效果:卡住你当前的线程
- 注意: 书写的位置,决定休眠哪儿个线程。
-
线程的6种状态:
- new 新建状态
- runnable 运行状态
- blocked 受阻塞状态
- waiting 等待状态
- timed waiting 休眠状态
- terminated 死亡状态
-
线程调用了start方法 就一定会进入运行状态吗?
- 不会,必须得到CPU的资源才会进入运行状态。
- 线程调用了start方法而是得到了CPU的执行权。
- 没有得到CPU执行资源的线程,会进入受阻塞状态。
- 当受阻塞状态的线程得到了CPU的执行资源,这是会从受阻塞—>运行状态。
- 不会,必须得到CPU的资源才会进入运行状态。
-
运行状态–>休眠状态 相当于放弃了 CPU的执行权
-
等休眠时间结束 重新获得CPU的执行权
-
等到用notify()方法 重新获得CPU的执行权
-
注意 :wait()和notify()方法是Object类中的方法
六种状态转换图:
线程休眠代码:
注意 : 父类中的run方法没有抛出异常
子类中只能自己处理(try…catch)
public class Kll {
public static void main(String[] args) throws InterruptedException {
// 线程休眠
// 单位毫秒
// 效果:卡住你当前的线程
// 注意: 书写的位置,决定休眠哪儿个线程
Thread.sleep(1000);
System.out.println("main");
TestBThread tb = new TestBThread();
tb.start();
}
}
class TestBThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
// 休眠一秒
// 注意 : 父类中的run方法没有抛出异常
// 子类中只能自己处理(try...catch)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}
}