I学霸官方免费教程三十九 :Java基础教程之线程

线程

线程和进程

进程:系统运行程序的最小单位;一个进程最少有一个线程
线程:程序执行任务的最小单位;线程与线程之间并行
一个进程至少有一个线程,在java中这个线程称为主线程,由系统创建,运行main方法。这样只有一个线程的程序也被称为单线程程序。
主线程从程序入口main方法开始执行代码,执行任意方法中的代码都是按照自上而下的顺序执行的,如果只有一个主线程,又想实现在线听音乐这个功能的话,就很难实现。因为主线程必须先去下载音乐;下载完成后,在执行播放音乐;这显然不能满足当今人们对在线听音乐的需求。所以现在的程序都是多线程的,就在线听音乐这个功能而言,可以在main方法中创建一个线程负责下载音乐,在创建一个线程负责播放音乐。这样在听音乐的同时,用于还可以进行其他操作。

创建线程

创建线程的两种方式
1、实现Runnable接口:还可以继承其他类
2、继承Thread类:使用简单

方式一:<span style="font-size: 14px;">实现Runnable接口</span>
package thread;
/**
 * 创建MyRunnable类,并实现Runnable接口 
 * @author 学霸联盟 - 赵灿
 */
public class MyRunnable implements Runnable {
	// 必须重写Runnable接口中的方法,不重写会出现语法错误
	// Runnable接口中只声明了一个方法run()
	@Override
	public void run() {
		// 线程执行的代码
		System.out.println("MyRunnable-run");
	}
}
方式二:
package thread; 
/**
 * 创建MyThread类,并继承Thread接口 
 * @author 学霸联盟 - 赵灿
 */
public class MyThread extends Thread {
	/*
	 * Thread类也实现了Runnable接口,并重写了接口中的run方法
	 * 所以此处如果没有重写run方法,不会出现语法错误,但创建的这个线程也就没有意义了
	 */
	@Override
	public void run() {
		// 线程执行的代码
		System.out.println("MyThread-run");
	}
}
package thread;
/**
 * 创建测试类Test,测试以上两种方式创建的线程 
 * @author 学霸联盟 - 赵灿
 */
public class Test {
	public static void main(String[] args) {
		/*********** 方式一 ************/
		// 创建一个MyRunnable类型的对象mr
		MyRunnable mr = new MyRunnable();
		// 创建一个线程对象t;并将mr作为参数传入Thread对象
		Thread t = new Thread(mr);
		/*
		 * 注意:启动线程调用的是Thread类中的start方法,而不是调用run方法;
		 * 如果直接调用run方法,将只表示run方法的调用,不会启动线程;
		 * 调用start方法启动线程t,线程启动后,会自动调用对象mr中的run方法
		 */
		t.start();

		/*********** 方式二 ************/
		// 创建一个MyThread类型的对象mt
		MyThread mt = new MyThread();
		// 因为start方法在Thread类中声明,MyThread类继承了Thread类
		// 所以此处使用对象mt调用的start方法是从父类Thread中继承的方法
		mt.start();
	}
}
输出结果:
MyRunnable-run
MyThread-run
或
MyThread-run
MyRunnable-run

由于多个线程是并行执行的,即同时运行。
就以上代码而言,会先执行t.start();再执行mt.start();但是由于这里的代码非常简单,在非常非常短的时间内,两个现场就启动完成了;而线程启动后并不是立即执行的,要等待调度程序选择哪个线程执行,所以此处启动的两个线程谁先执行并不能确定。所以输出顺序也不确定。

线程的生命周期

新建(初始态):执行new操作后。此时在已经在内存中创建出了线程对象,但线程还没有启动运行
可运行:调用start()方法后。此时线程已经启动,但还没有运行(线程的执行是通过CPU执行完成的),另一种说法是:还没有获得CPU的使用权;正在和其他可运行状态的线程一起等待系统的调度程序选取,选中哪个线程,哪个现在使用CPU执行程序,执行一定的时间(CPU的时间片)后,退出对CPU的占用,转入可运行状态,和其他线程一起等待系统调度程序的选取。
运行:已获得CPU的使用权,正在运行
阻塞:执行sleep(int)、yield()、join()、wait()方法后,阻塞状态的线程不会被调度程序选中。只有从阻塞状态恢复至可运行态以后,才有机会获得CPU的使用权
死亡:运行结束或执行stop()、destroy()方法后;这两个方法均已过时,不推荐使用;此时线程已经彻底停止运行,释放了线程所占用的资源。

线程的调度

sleep方法

static void sleep(int)静态方法,建议使用类名Thread调用;
作用:线程休眠;哪个线程执行Thread.sleep();这条语句,哪个线程就会休眠(阻塞);int类型的参数,代表线程休眠的时间(毫秒),时间结束自动恢复至可运行态,和其他线程一起等待调度程序的选取
一句话:谁执行,谁休眠。

实例:
package thread.sleep;
/**
* 创建SleepDemo类
* 用于测试sleep方法
* @author 学霸联盟 - 赵灿
*/
public  class  SleepDemo{
	public  static  void  main(String[]  args){ 
		System.out.println("主线程正在执行");
		System.out.println("主线程休眠开始");
		// 执行Thread.sleep();可能产生异常,使用try-catch语句捕获异常
		try {
			// 这条语句会被主线程执行,执行后主线程休眠1000毫秒(1秒)
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// 如果try中的代码产生异常,程序执行这条输出语句
			System.out.println("线程休眠时出现异常");
		}
		System.out.println("主线程休眠结束");
		System.out.println("主线程恢复执行");
	}
}
输出结果:
主线程正在执行
主线程休眠开始【这里会休眠(停止)1秒,1秒后继续输出以下内容】
主线程休眠结束
主线程恢复执行

yield方法

static void yield()静态方法,建议使用类名Thread调用。
作用:线程让步;哪个线程执行Thread.yield();语句,哪个线程就会把已经获得的CPU使用权让出来,并进入可运行状态,和其他线程一起等待调度程序的选取;
一句话:谁执行,谁让步。

实例:
package thread.yield;
/**
 * 创建YieldDemo类
 * 用于测试线程的让步执行
 * @author 学霸联盟 - 赵灿
 */
public  class  YieldDemo {
	public  static  void  main(String[]  args) {
		//声明ThreadA和ThreadB的对象
		ThreadA  ta = new  ThreadA();
		ThreadB  tb = new  ThreadB();
		//启动线程ta
		ta.start();
		//启动线程tb
		tb.start();
	}
}

/**
 * 创建ThreadA类,并继承Thread类
 * @author 学霸联盟 - 赵灿
 */
class  ThreadA  extends  Thread{
	//重写父类中的run方法
	@Override
	public  void  run() {
		//循环30次
		for (int  i  = 1;  i  <=  30;  i ++) {
			/*
			 * 每循环一次ThreadA类的对象(本例是ta)就会让出一次CPU的使用权,
			 * 给其他线程执行(这个例子中是主线程和ThreadB的对象tb)
			 */
			Thread.yield();
			//输出一个字符串,为了在结果中可以看到线程ta的执行频率
			System.out.println("ThreadA-"  +  i);
		}
	}
}

/**
 * 创建ThreadB类,并继承Thread类
 * @author 学霸联盟 - 赵灿
 */
class  ThreadB  extends  Thread{
	//重写父类中的run方法
	@Override
	public  void  run() {
		//循环30次
		for (int  i  = 1;  i  <=  30;  i ++) {
			//输出一个字符串,为了在结果中可以看到线程tb的执行频率
			System.out.println("ThreadB--"  +  i);
		}
	}
}
输出结果:输出顺序是不确定的;多数情况下,线程tb会先执行完,线程ta后执行完,而且线程tb的执行频率要比线程ta高,但不是绝对的

join方法

void  join([int] [,int]);非静态方法,只能使用对象调用。
作用:线程插队;假设现在有线程A和B,线程A中执行了B.join();语句,线程B会插队到线程A前执行,线程A会被阻塞
一句话:谁调用,谁插队;谁执行,谁阻塞。
其中可以传入一个int类型的参数,代表插队的毫秒数,如果传入两个int类型的参数,代表插队的毫秒数(左)和纳秒数(右);插队时间结束后,插队线程和被阻塞线程都回到可运行状态,等待调度程序的选取

实例:
package thread.join;
/**
 * 创建JoinDemo类
 * 用于测试线程的让步执行
 * @author 学霸联盟 - 赵灿
 */
public class JoinDemo {
	public  static  void  main(String[]  args) {
		//创建ThreadA的对象ta
		ThreadA  ta = new  ThreadA();
		//启动线程ta
		ta.start();
	}
}

/**
 * 创建ThreadA类,并继承Thread类
 * @author 学霸联盟 - 赵灿
 */
class  ThreadA  extends  Thread{
	//重写父类中的run方法
	@Override
	public  void  run() {
		//创建ThreadB的对象tb;线程ta运行后便会先执行此句
		ThreadB  tb = new  ThreadB();
		//启动线程tb;线程tb启动后,此时线程ta和tb共同等待调度程序的选取
		tb.start();
		//循环30次
		for (int  i  = 1;  i  <=  30;  i ++) {
			/*
			 * 当i等于10时,执行tb.join();
			 * 使线程tb插队执行到线程ta前面执行
			 * 线程ta被阻塞
			 */
			if ( i == 10 ) {
				try {
					/*
					 * 只需插队一次即可
					 * 在i小于10时,线程ta和tb共同等待调度程序的选取执行
					 * i==10时,执行tb.join();
					 * 执行后,线程ta被阻塞,只执行线程tb;
					 * 直至线程tb执行完,ta才会恢复至可运行态
					 * 其中ta是代码的执行者,tb是代码的调用者
					 */
					tb.join();
				} catch (InterruptedException e) {
					//输出栈内存中的异常信息
					e.printStackTrace();
				}
			}
			//输出一个字符串,为了在结果中可以看到线程ta的执行频率
			System.out.println("ThreadA-"  +  i);
		}
	}
}

/**
 * 创建ThreadB类,并继承Thread类
 * @author 学霸联盟 - 赵灿
 */
class  ThreadB  extends  Thread{
	//重写父类中的run方法
	@Override
	public  void  run() {
		//循环30次
		for (int  i  = 1;  i  <=  30;  i ++) {
			//输出一个字符串,为了在结果中可以看到线程tb的执行频率
			System.out.println("ThreadB--"  +  i);
		}
	}
}
由于输出结果的顺序完全不确定,这里同学们一定要自行测试
时间: 2024-10-29 12:56:09

I学霸官方免费教程三十九 :Java基础教程之线程的相关文章

I学霸官方免费教程三十:Java基础教程之泛型

泛型 先给大家举个例子:如现在有一家工厂,可以生产手机,也可以生产电脑.以后还可能生产其他产品.如果给某个工厂加上了泛型,就规定了这个工厂只能生产手机或电脑,不能再生产其他产品了. 实例: package generic; /**  * 产品枚举Product  * @author 学霸联盟 - 赵灿  */ public enum Product { 手机,电脑 } package generic; /**  * 手机类Phone  * @author 学霸联盟 - 赵灿  */ public

I学霸官方免费教程四十 :Java基础教程之线程同步

线程的同步 指当多个线程使用同一对象中被同步的资源时,要根据"先来后到"的顺序使用.举个例子:现在只有一台电脑,现在有两个人A和B想玩游戏,一个人C想写代码,一个人D想听音乐.此时A.B.C三个人要抢这台电脑,谁先抢到谁用,用完了后面两个人在接着抢,谁抢到谁用.而D则不用,在另外三个人中任意一个人正在使用的时候,都可以播放音乐给他听:由此可以看出玩游戏和写代码的功能(方法)是要有"先来后到"的顺序的,而听音乐这个功能不需要.所以玩游戏和写代码的方法就是需要被同步的,

I学霸官方免费教程三十:Java集合框架之List集合

集合框架 在数组的使用过程中可以看到,想要向数组中插入元素和删除元素非常麻烦,而且数组的长度是无法改变的.java为我们提供了批量存储数据更加方便的容器,就是集合. 集合和数组的作用一样,都是为了使用一个变量来存储一批数据的:但集合使用起来更加方便,而且集合的长度是可以变化的. List接口 List集合可以存储有序的,可重复的数据: 常用的子类是ArrayList和LinkedList两个类 ArrayList类 这是一个底层由数组实现的集合类,是对数组进行了封装. 实例: package c

I学霸官方免费教程四十一 :Java基础教程之线程死锁

线程死锁 是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的线程称为死锁线程. 例如:某一商店有两个人PS和PB在做交易,PS手里拿着货物对PB说,你先给我钱我在给你货,而PB拿着钱对PS说你先给我货我在给你钱.两个人就此僵持下去,永远也无法做成交易,这就构成了死锁. 实例: package thread.deadlock; /** * 创建DeadlockDe

I学霸官方免费教程三十二:Java集合框架之Set集合

Set接口 Set集合是无序的.元素不可重复的结合常用集合类有HashSet和TreeSet HashSet类常用的两种List集合各有各的优点,那么有没有同时具备这两种List集合的优点的集合呢?答案是肯定的,就是Set集合. 实例: package collection.set.hashSet; import java.util.HashSet; import java.util.Iterator; /**  * 演示HashSet  * @author 学霸联盟 - 赵灿  */ publ

I学霸官方免费教程三十一:Java集合框架之List集合

集合框架 在数组的使用过程中可以看到,想要向数组中插入元素和删除元素非常麻烦,而且数组的长度是无法改变的.java为我们提供了批量存储数据更加方便的容器,就是集合.集合和数组的作用一样,都是为了使用一个变量来存储一批数据的:但集合使用起来更加方便,而且集合的长度是可以变化的. List接口 List集合可以存储有序的,可重复的数据:常用的子类是ArrayList和LinkedList两个类 ArrayList类 这是一个底层由数组实现的集合类,是对数组进行了封装. 实例: package col

NeHe OpenGL教程 第三十九课:物理模拟

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十九课:物理模拟 物理模拟简介: 还记得高中的物理吧,直线运动,自由落体运动,弹簧.在这一课里,我们将创造这一切. 物理模拟介绍 如果你很熟悉物理规律,并且想实现它,这篇文章很适合你. 在这篇教程里,你会创建一个非常简单的物理引

I学霸官方免费教程一:Java软件开发预备知识

一.     计算机系统简介 1.硬件系统:看得见,摸得着 主机:主机箱.主板.内存.硬盘.CPU(中央处理器).声卡.显卡.网卡 外设:显示器.音响 输入设备:键盘.鼠标.扫描仪 输出设备:显示器.投影仪.音响 2.软件系统 系统软件:windows.Linux.IOS.Unix.Android: 编译软件:编程语言,编译器,解释器 应用软件:除了以上的全是应用软件,比如聊天软件,网站,游戏软件等等 二.     软件简介 软件:按照特定顺序组织的计算机数据和指令的集合:其中指令是指挥计算机如

Python进阶(三十九)-数据可视化の使用matplotlib进行绘图分析数据

Python进阶(三十九)-数据可视化の使用matplotlib进行绘图分析数据 ??matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中. ??它的文档相当完备,并且 Gallery页面 中有上百幅缩略图,打开之后都有源程序.因此如果你需要绘制某种类型的图,只需要在这个页面中浏览/复制/粘贴一下,基本上都能搞定. ??在Linux下比较著名的数据图工具还有gnuplot