Java学习笔记之线程(一):线程的创建和生命周期



package com.demo;

/**
 * 	进程:正在运行的程序叫做进程,进程负责了这个程序的内存空间分配,代表了内存中的执行区域;
 * 
 * 	问题:Windows号称是多任务的操作系统,那么Windows是同时运行多个应用程序吗?
 * 		从宏观角度:从感知和能看得到的现象来说,确实是同时运行多个应用程序的;
 * 		从微观角度:由于CPU分时机制的作用,使每个进程都能循环获得自己的CPU时间片,但因为轮换速度非常快,
 * 				所以看起来好像所有的程序都在同时运行一样;	
 * 
 * 	线程:线程在一个进程中负责了代码的执行,就是进程中一个执行路径;
 * 	多线程:就是在一个进程中多个执行路径同时执行;
 * 
 * 	运行任何一个Java程序,jvm在运行的时候都会创建一个main线程,来执行main方法中的所有代码;
 * 
 * 	问题:一个java程序至少有几个线程?
 * 		至少有两个线程,一个是主线程负责main方法代码的执行,一个是垃圾回收器线程,负责垃圾的回收;
 * 
 * 	多线程的好处:
 * 		1、解决了一个进程能同时执行多个任务的问题;
 * 		2、提高了资源的利用率,而不是提高效率;
 * 	多线程的弊端:
 * 		1、对线程进行管理要求额外的CPU开销,增加了CPU的负担;
 * 		2、降低了一个进程中线程的执行效率;
 * 		3、引发了线程安全问题;当多个线程需要对公有资源进行操作时,后一个线程往往会修改掉前一个线程保存的数据;
 * 		4、出现了死锁现象;即较长时间的等待或资源竞争;
 * 
 * 	线程的创建有两种方法:
 * 		方法一:
 * 			1、自定义一个类继承Thread类;
 * 			2、重写Thread类的 run() 方法;
 * 				问题:为什么要重写 run() 方法?
 * 				每个线程都有自己的任务代码,jvm创建的主线程的任务代码就是 main() 方法中的所有代码,
 * 				而自定义线程的任务代码就是run() 方法中的所有代码。
 *			3、创建Thread的子类对象,并且调用 start() 方法开启线程;
 *				注意:一个自定义线程一旦开启,就会执行 run() 方法中的任务代码;run() 方法不能直接调用,
 *				因为直接调用就相当于调用了一个普通方法,并没有开启线程;
 * 
 * 	线程的生命周期:如下图所示:
 * 		CPU的等待资格:具有CPU等待资格的线程,表示CPU在切换的时候有可能执行的线程;
 * 		CPU的执行权:具有CPU执行权的线程,表示CPU正在执行的线程;
 * 	
 * 		1、Demo1 d = new Demo1():当线程对象被 new 出来的时候,线程处于“创建状态”,该状态下的线程不具备任何资格;
 * 		2、d.start():调用线程的 start() 方法,线程进入“可运行状态”,该状态的线程具备CPU等待资格,不具备CPU执行权;
 * 		3、当线程得到CPU的执行权,进入“运行状态”,此时线程具备CPU的执行权,也具备CPU的等待资格;
 * 		4、如果线程在执行过程中被抢走了CPU的执行权,线程将重新进入“可运行状态”;
 * 		5、当线程执行完任务代码后,就进入了“死亡状态”。
 * 		6、除了 “创建状态->可运行状态->运行状态->死亡状态”,这四种正常状态之外,线程还存在一种“临时阻塞状态”;
 * 			当“运行状态”下的线程执行了 sleep() 方法或者 wait() 方法,线程就会进入“临时阻塞状态”;
 * 			如果线程是调用了sleep()方法进入的“临时阻塞状态”,那么一旦超过指定的睡眠时间,就会重新进入“可运行状态”;
 * 			如果线程是调用了wait()方法进入的“临时阻塞状态”,那么需要其他线程唤醒该线程,才可以重新进入“可运行状态”;
 * 
 */

public class Demo1 extends Thread {
		
	@Override
	public void run() {
		// 执行自定义线程的任务代码
		for (int i = 0; i < 100; i++){
			System.out.println("自定义线程: " + i);
		}
	}

	public static void main(String[] args) {
		
		// 创建自定义线程对象
		Demo1 d = new Demo1();
		//d.run();	// 没有开启线程,只是在主线程中调用了一个普通方法
		d.start();	// 启动线程
		
		for (int i = 0; i < 100; i++){
			System.out.println("main线程: " + i);
		}
		
	}
	
}




package com.demo;

/*
 * 	线程的创建方式二:
 * 		1、自定义一个类实现Runnable接口;
 * 		2、实现Runnable接口的run方法,把自定义线程的任务代码写在run方法上;
 * 		3、创建Runnable实现类对象;
 * 		4、创建Thread类的对象,并且把Runnable实现类的对象作为实参传递;
 * 		5、调用Thread对象的start()方法开启线程;
 * 
 * 	问题1:请问Runnable实现类的对象是线程对象吗?
 * 		不是线程对象,只不过是实现了Runnable接口的普通对象而已;
 * 		只有Thread或者Thread的子类对象才是线程对象;
 * 
 * 	问题2:为什么要把Runnable实现类的对象作为实参传递给Thread对象?作用是什么?
 * 		从Thread类的源码可以看出,创建Thread对象的时候,可以把Runnable实现类的对象传递过去,用target保存;
 * 		public Thread(Runnable target, String name) {
 * 			init(null, target, name, 0);
 *		} 
 *		当调用Thread对象的start()方法开启线程的时候,实际上就是执行了Thread对象的run()方法,源码如下:
 *		@Override
 *		public void run() {
 *			if (target != null) {
 *				target.run();
 *			}
 *		}
 *		可以看出,执行run()方法的时候,实际上就是执行Runnable实现类的run()方法;
 *		作用也就是把Runnable实现类的对象的run()方法,作为线程的任务代码去执行;
 * 
 */

public class Demo6 implements Runnable {
	
	// 2、实现Runnable接口的run方法,把自定义线程的任务代码写在run方法上;
	@Override
	public void run() {
		
		System.out.println("this:" + this);	// 此处this表示当前类对象,不是当前线程对象;
		System.out.println("Thread.currentThread():" + Thread.currentThread());
		
		for (int i = 0; i < 50; i++){
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
		
	}
	
	public static void main(String[] args) {
		
		// 3、创建Runnable实现类对象;
		Demo6 d = new Demo6();		
		// 4、创建Thread类的对象,并且把Runnable实现类的对象作为实参传递;
		Thread t = new Thread(d, "自定义线程");		
		// 5、调用Thread对象的start()方法开启线程;
		t.start();
		
		for (int i = 0; i < 50; i++){
			System.out.println("main线程:" + i);
		}
	}

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值