一个程序完全入门Java多线程

代码只供学习使用,实际开发中建议遵守Java开发规范,合理分包,不要忽视面向对象方法的重要原则:封装

代码所涉及知识点:

什么是线程、Thread方法和Runnable接口的介绍及创建线程、线程的状态和生命周期、sleep方法和join方法的使用、线程的优先级、线程同步、线程间通信(见另一篇文章,点击访问,Java多线程之——线程间通信实例

package practice;

/**
 * 
 * @author slvayf
 * 
 */

// 通过继承Thread类的方式,可以完成多线程的建立,多线程由系统调度交叉执行
class MyThread extends Thread {
	// 父类引用,传参修改线程名称
	public MyThread(String name) {
		super(name);
	}

	public void run() {
		for (int i = 1; i < 6; i++) {
			// sleep方法:
			// 通过sleep方法使线程休眠(暂停线程的执行1毫秒)
			// 但是暂停1毫秒后,线程并不会马上进入执行状态,而是进入可执行状态(Runnable)
			// 执行thread类的sleep方法,多次运行程序我们可以发现:
			// ___“通过Runnable接口创建的线程”因为不休眠而“通过thread方法创建的线程:线程0、1、2”1毫秒休眠一次
			// 所以“通过Runnable接口创建的线程”获得CPU使用权开始执行的概率会更大
			// 不过,因为“通过thread方法创建的线程:线程0”执行时虽然1毫秒休眠一次,但因为使用join方法,它是优先执行的
			// “通过Runnable接口创建的线程”也可以使用thread类的sleep方法实现类似效果,join相同
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				// 休眠中断异常
				e.printStackTrace();
			}
			System.out.println(getName() + "正在执行第" + i + "次");
		}
	}
}

// 但是继承Thread类这种方式有一个局限性,如果一个类已经有了自己的父类,就不可以继承Thread类,因为java规定类是单继承的
// 如果该类中的还有部分代码需要被多个线程同时执行,只有对该类进行额外的功能扩展,java就提供了一个接口Runnable
// Runnable接口中定义了run方法,其实run方法的定义就是为了存储多线程要运行的代码
// 所以,通常创建线程都用第二种方式,因为,实现Runnable接口可以避免单继承的局限性
// 而且,继承Thread,是可以对Thread类中的方法进行子类复写的
// 但是不需要做这个复写动作,只为定义线程代码存放位置的话,实现Runnable接口更方便一些
// 所以,Runnable接口将线程要执行的任务封装成了对象
// 其实,将多线程要运行的代码的位置单独定义到接口中,为其他类进行功能扩展提供了前提
// 所以,Thread类在描述线程时,内部定义的run方法,也来自于Runnable接口
class PrintRunnable implements Runnable {

	@Override
	public void run() {
		for (int i = 1; i < 6; i++) {
			System.out.println(Thread.currentThread().getName() + "正在执行第" + i + "次"+ " 优先级:" + Thread.currentThread().getPriority());
			// 主线程和新创建线程默认优先级为5
			// 设置t2的优先级为10,多次执行下来我们可以发现,在大多数情况下,t2是要比t1优先执行的,优先级先10后5
			// 但有时候t1("通过Runnable接口创建的线程:线程1")还是在t2之前执行
			// 其原因是,操作系统确定程序执行优先级,并不是只根据用户设置的优先级,还要综合计算机内存及其它资源利用状况,做出综合判断
			// 比如先启动的低优先级的程序t1,由于所需资源和运行时间少,可能在很短时间内全部执行完成
		}
	}
}

// 两个线程同步(线程互斥)的测试类,连续两次对100减10,每减一次输出一次,区别如下:
// ThreadSynchronization1对象未锁定,两个线程随机执行,执行次数无法计数故由线程名输入,结果为 90 90,结果异常
// ThreadSynchronization2对象锁定(使用synchronized关键字),两个线程顺序执行,因为是顺序执行,所以执行次数可以累加(k),结果为 90 80,结果正常
// synchronized关键字可以用在成员方法、静态方法和代码块
class ThreadSynchronization1 implements Runnable {
	private int i = 100, j = 10, ans;

	@Override
	public void run() {
		ans = this.i - j;
		// 线程休眠1秒,模拟线程异常
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.i = ans;
		System.out.println("未锁定ThreadSynchronization的对象时第" + Thread.currentThread().getName() + "次减10:" + this.i);
	}
}

class ThreadSynchronization2 implements Runnable {
	private int i = 100, j = 10, ans, k = 1;

	@Override
	public synchronized void run() {
		ans = this.i - j;
		// 线程休眠1秒,模拟线程异常
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.i = ans;
		System.out.println("锁定ThreadSynchronization的对象后第" + k + "次减10:" + this.i);
		k++;
	}
}

public class MultiThreading {
	public static void main(String[] args) {
		// 查看主线程优先级
		System.out.println("--主线程的优先级为:" + Thread.currentThread().getPriority());
		// MyThread、PrintRunnable类的对象实例化
		MyThread mt0 = new MyThread("通过thread方法创建的线程,使用join抢先执行:线程0");
		MyThread mt1 = new MyThread("通过thread方法创建的线程,使用sleep延迟执行:线程1");
		MyThread mt2 = new MyThread("通过thread方法创建的线程,使用sleep延迟执行:线程2");
		PrintRunnable pr1 = new PrintRunnable();
		PrintRunnable pr2 = new PrintRunnable();
		ThreadSynchronization1 ts1 = new ThreadSynchronization1();
		ThreadSynchronization2 ts2 = new ThreadSynchronization2();
		// 创建Thread类对象,参数1为:基于Runnable接口实现类的对象,参数2为:线程名
		Thread t1 = new Thread(pr1, "通过Runnable接口创建的线程:线程1");
		Thread t2 = new Thread(pr2, "通过Runnable接口创建的线程:线程2");
		Thread tsTest1 = new Thread(ts1, "1");
		Thread tsTest2 = new Thread(ts1, "2");
		Thread tsTest3 = new Thread(ts2);
		Thread tsTest4 = new Thread(ts2);
		// 启动线程(Thread类的start方法),使线程进入可运行(Runnable)状态
		mt0.start();
		// 调用join方法,mt0抢占资源优先执行
		// mt0.join(10); 指:mt0线程在优先执行的情况下执行10毫秒,不论是否执行完毕,都将让出自己占用的资源,退出优先状态
		try {
			mt0.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		mt1.start();
		mt2.start();
		t1.start();
		t2.start();
		// 设置t2的优先级最高,为10
		t2.setPriority(10);
		// 启动线程同步测试
		tsTest1.start();
		tsTest2.start();
		tsTest3.start();
		tsTest4.start();
	}
}

一个可参考的运行结果:(为方便观察,输出结果做了空行分隔处理)

--主线程的优先级为:5

通过thread方法创建的线程,使用join抢先执行:线程0正在执行第1次
通过thread方法创建的线程,使用join抢先执行:线程0正在执行第2次
通过thread方法创建的线程,使用join抢先执行:线程0正在执行第3次
通过thread方法创建的线程,使用join抢先执行:线程0正在执行第4次
通过thread方法创建的线程,使用join抢先执行:线程0正在执行第5次

通过Runnable接口创建的线程:线程2正在执行第1次 优先级:10
通过Runnable接口创建的线程:线程2正在执行第2次 优先级:10
通过Runnable接口创建的线程:线程2正在执行第3次 优先级:10
通过Runnable接口创建的线程:线程2正在执行第4次 优先级:10
通过Runnable接口创建的线程:线程2正在执行第5次 优先级:10

通过Runnable接口创建的线程:线程1正在执行第1次 优先级:5

通过thread方法创建的线程,使用sleep延迟执行:线程1正在执行第1次

通过Runnable接口创建的线程:线程1正在执行第2次 优先级:5
通过Runnable接口创建的线程:线程1正在执行第3次 优先级:5
通过Runnable接口创建的线程:线程1正在执行第4次 优先级:5
通过Runnable接口创建的线程:线程1正在执行第5次 优先级:5

通过thread方法创建的线程,使用sleep延迟执行:线程1正在执行第2次
通过thread方法创建的线程,使用sleep延迟执行:线程2正在执行第1次
通过thread方法创建的线程,使用sleep延迟执行:线程2正在执行第2次
通过thread方法创建的线程,使用sleep延迟执行:线程1正在执行第3次
通过thread方法创建的线程,使用sleep延迟执行:线程2正在执行第3次
通过thread方法创建的线程,使用sleep延迟执行:线程1正在执行第4次
通过thread方法创建的线程,使用sleep延迟执行:线程1正在执行第5次
通过thread方法创建的线程,使用sleep延迟执行:线程2正在执行第4次
通过thread方法创建的线程,使用sleep延迟执行:线程2正在执行第5次

未锁定ThreadSynchronization的对象时第1次减10:90
未锁定ThreadSynchronization的对象时第2次减10:90
锁定ThreadSynchronization的对象后第1次减10:90
锁定ThreadSynchronization的对象后第2次减10:80

 

你可能感兴趣的:(JavaSE,Java多线程,Thread类创建线程,Runnable接口创建线程,线程的状态和生命周期)