考试大纲之Java多线程

多线程是Java语言的一个重要特征,利用多线程技术可以使系统同时运行多个程序块,缩短了程序的响应时间,提高了计算机资源的利用率,达到了多任务处理的目的。

进程与线程
  • 进程:进程是程序的一次动态执行过程,每个程序都有自己独特的内存空间,一个应用程序可以启动多个应用空间,我们拿Chrome来举例。
    在这里插入图片描述
  • 线程:线程是进程中的一个执行流程,一个进程可以由多个线程组成,即一个进程中可以同时运行多个不同的线程,每个线程完成不同的任务。

没有进程就不会有线程,进程与线程是整体与局部的关系,进程与线程的关系如图1-1所示。
在这里插入图片描述

图1-1
线程的生命周期

线程在完整的生命周期中要经历5种状态,分别是新建、就绪、运行、阻塞和死亡。状态关系如图1-2所示。
在这里插入图片描述

图1-2
实现线程的两种方式
  1. 继承Thread类
    在java.lang包中定义了Thread类,一个类继承了Thread类,此类就称为多线程实现类。
    例子:
    Test_Thread.java
package com.hcybx;

public class Test_Thread extends Thread{//继承Thread
   private String name;
   public Test_Thread(String name) {
   	this.name = name;
   }
   
   public void run() {//覆盖Thread中的run()方法
   	for (int i = 1; i < 5; i++) {
   		System.out.println(name+"运行,i="+i);
   	}
   }
}

Test.java

package com.hcybx;

public class Test {
	public static void main(String[] args) {
		Test_Thread tt1 = new Test_Thread("A");//实例化线程对象
		Test_Thread tt2 = new Test_Thread("B");
		Test_Thread tt3 = new Test_Thread("C");
		Test_Thread tt4 = new Test_Thread("D");
		Test_Thread tt5 = new Test_Thread("E");
		Test_Thread tt6 = new Test_Thread("F");
		Test_Thread tt7 = new Test_Thread("G");
		Test_Thread tt8 = new Test_Thread("H");
		tt1.run();//启动多线程
		tt2.run();
		tt3.run();
		tt4.run();
		tt5.run();
		tt6.run();
		tt7.run();
		tt8.run();
	}
}

运行结果:
在这里插入图片描述
2. 实现Runnable接口(使用多个线程共享资源,利用Runnable来完成)
通过实现Runnable接口来实现多线程。
Runnale接口的定义:

package com.hcybx;

public class Test_Runnable implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}
	
}

利用Runnable子类来启动多线程分为三个步骤。
1.实例化Runnable子类对象。
2.利用Runnable对象作为参数,实例化Thread对象。
3.利用Thread对象的start方法启动线程。

继承Thread类和实现Runnable接口的资源共享区别。(金典例题:卖飞机票)

1.通过继承Thread类来实现卖飞机票

package com.hcybx;

public class ThreadSell extends Thread {
	private int ticket = 3;// 假如还剩三张飞机票
	private String sellName;// 售票机

	public ThreadSell(String sellName) {
		this.sellName = sellName;
	}

	public void run() {
		for (int i = 0; i < 20; i++) {
			if (ticket > 0) {
				System.out.println(sellName + "卖出第" + ticket-- + "张票");
			}
		}
	}
}

2.通过实现Runnable接口来实现卖飞机票

package com.hcybx;

public class RunnableSell implements Runnable {
	private int ticket = 3;

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			if (ticket > 0) {
				System.out.println(Thread.currentThread().getName() + "卖出第" + ticket-- + "张票");
			}
		}

	}

}

3.启动线程

package com.hcybx;

public class SellEngine {
	//Thread实现多线程
	public static void sellThread() {
		ThreadSell sell1 = new ThreadSell("售票机一");
		ThreadSell sell2 = new ThreadSell("售票机二");
		ThreadSell sell3 = new ThreadSell("售票机三");
		ThreadSell sell4 = new ThreadSell("售票机四");
		ThreadSell sell5 = new ThreadSell("售票机五");
		sell1.start();
		sell2.start();
		sell3.start();
		sell4.start();
		sell5.start();
	}
	
	//Runnable实现多线程
	public static void sellRunnable() {
		RunnableSell sell = new RunnableSell();
		Thread t1 = new Thread(sell, "售票机一");
		Thread t2 = new Thread(sell, "售票机二");
		Thread t3 = new Thread(sell, "售票机三");
		Thread t4 = new Thread(sell, "售票机四");
		Thread t5 = new Thread(sell, "售票机五");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
	}
}

4.开始卖票

package com.hcybx;

public class TestSell {
	public static void main(String[] args) {
		System.out.println("Thread方式");
		SellEngine.sellThread();
		try {
			Thread.sleep(2000);//线程执行暂停2秒
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("Runnable方式");
		SellEngine.sellRunnable();
	}
}

运行结果:
在这里插入图片描述

所以我们在实际开发中,实现Runnable接口相比继承Thread类可以避免单继承带来的局限。因此一般采用实现Runnable接口来实现多线程。

同步

再次回到飞机票的问题,假设全国飞机票系统中,存在多个人同时订同一个机次的飞机票,那么机票是共享资源,每个人的预购系统是一个线程,这样存在多个线程对一个资源进行操作的问题。
问题引出:

package com.hcybx;

public class SellTicket implements Runnable{
	private int ticket = 5;  //假设还有5张票
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			if (ticket > 0) {
				try {
					Thread.sleep(1000);//延迟
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println("卖出第"+ticket--+"张票");
			}
		}
		
	}
	
}

package com.hcybx;

public class TestSell {
	public static void main(String[] args) {
		SellTicket st = new SellTicket();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		Thread t3 = new Thread(st);
		t1.start();
	    t2.start();
	    t3.start();
	}
}

多次运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

出现上面的根本原因就是程序代码被多个线程共享而交替运行,解决它的关键是==确保共享的代码块在某个时间被一个线程所拥有。==在Java语言中就可以利用同步解决问题。

package com.hcybx;

public class SellTicket implements Runnable {
	private int ticket = 5; // 假设还有5张票

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			synchronized (this) {
				if (ticket > 0) {
					try {
						Thread.sleep(1000);// 延迟
					} catch (Exception e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"卖出第" + ticket-- + "张票");
				}
			}
		}
	}
}

package com.hcybx;

public class TestSell {
	public static void main(String[] args) {
		SellTicket st = new SellTicket();
		Thread t1 = new Thread(st,"售票点一");
		Thread t2 = new Thread(st,"售票点二");
		Thread t3 = new Thread(st,"售票点三");
		t1.start();
	    t2.start();
	    t3.start();
	}
}

在这里插入图片描述
在这里插入图片描述
使用同步代码块就可以解决共享资源时的正确性问题啦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章