欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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的执行权

  • 等到用notify()方法 重新获得CPU的执行权

  • 注意 :wait()和notify()方法是Object类中的方法

六种状态转换图:java之线程创建的两种方式,六种状态和匿名内部类创建子类或实现类对象
线程休眠代码:
注意 : 父类中的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);
			
		}
	}
}