java之线程创建的两种方式,六种状态和匿名内部类创建子类或实现类对象

一.匿名内部类创建子类或实现类对象

 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类中的方法

六种状态转换图:在这里插入图片描述
线程休眠代码:
注意 : 父类中的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);
			
		}
	}
}

猜你喜欢

转载自blog.csdn.net/KongLingLei_08225/article/details/82762897