第14章 多线程基础
第14章 多线程基础14.1 线程相关概念
14.1.1 程序(program)
是为完成特定任务,用某种语言编写的一组指令的集合,即编写的代码。
示例代码(以Java为例):
public class BallMove extends JFrame {
MyPanel mp = null;
public static void main(String[] args) {
BallMove ballMove = new BallMove();
}
public BallMove() {
mp = new MyPanel();
this.add(mp);
this.setSize(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}14.1.2 进程
[*]运行中的程序,如启动QQ、迅雷,操作系统会为其分配内存空间。
[*]是程序的一次执行过程,有产生、存在和消亡的动态过程 。
14.1.3 线程
[*]由进程创建,是进程的实体,一个进程可拥有多个线程 。
[*]举例:后续会将多线程加入“坦克大战”游戏实践。
14.1.4 其他相关概念
[*]单线程:同一时刻仅允许执行一个线程。
[*]多线程:同一时刻可执行多个线程,如QQ同时开多个聊天窗口、迅雷同时下载多个文件 。
[*]并发:同一时刻多个任务交替执行,单CPU实现“貌似同时” 。
[*]并行:同一时刻多个任务真正同时执行,多核CPU可实现,Java支持。
14.2 线程基本使用
14.2.1 创建线程的两种方式(Java)
[*]继承Thread类:重写run方法,定义线程执行逻辑。
[*]实现Runnable接口:重写run方法,解决Java单继承局限,更灵活。
14.2.2 应用案例1 - 继承Thread类
package com.ming.threaduse;
/**
* @author 明
* @version 1.0
* 演示通过继承Thread 类创建线程
*/
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
//创建Cat对象,可以当做线程使用
Cat cat = new Cat();
//读源码
/*
(1)
public synchronized void start() {
start0();
}
(2)
//start0() 是本地方法,是JVM调用, 底层是c/c++实现
//真正实现多线程的效果, 是start0(), 而不是 run
private native void start0();
*/
//cat.run();//run方法就是一个普通的方法, 没有真正的启动一个线程,就会把run方法执行完毕,才向下执行
//说明: 当main线程启动一个子线程 Thread-0, 主线程不会阻塞, 会继续执行
//这时 主线程和子线程是交替执行..
cat.start();//启动线程-> 最终会执行cat的run方法
System.out.println("主线程继续执行" +Thread.currentThread().getName());
for (int i = 0; i < 10; i++) {
System.out.println("主线程 i= " + i);
//让主线程休眠
Thread.sleep(1000);
}
}
}
//说明
//1.当一个类继承了Thread类,该类就可以当作线程使用
//2. 我们会重写 run方法,写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的run方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
class Cat extends Thread{
int times = 0;
@Override
public void run() {//重写run方法,写上自己的业务逻辑
while (true) {
System.out.println("喵喵,我是小猫咪"+times++ + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(times==8){
break;
}
}
}
}
14.2.3 应用案例2 - 实现Runnable接口
需求:每隔1秒在控制台输出“hi!”,输出10次后退出。
实现:
package com.ming.threaduse;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* @author 明
* @version 1.0
* 通过实现接口Runnable 来开发线程
*/
public class Thread02 {
public static void main(String[] args) throws InterruptedException {
// Dog dog = new Dog();
// //dog.start(); 这里不能调用start
// //创建了Thread对象,把 dog对象(实现Runnable),放入Thread
// Thread thread = new Thread(dog);
// thread.start();
Tiger tiger = new Tiger();
ThreadProxy threadProxy = new ThreadProxy(tiger);
threadProxy.start();
}
}
class Animal {
}
class Tiger extends Animal implements Runnable {
@Override
public void run() {
System.out.println("老虎嗷嗷叫....");
}
}
//线程代理类 , 模拟了一个极简的Thread类
class ThreadProxy implements Runnable {//你可以把Proxy类当做 ThreadProxy
private Runnable target = null;//属性,类型是 Runnable
@Override
public void run() {
if (target != null) {
target.run();//动态绑定(运行类型Tiger)
}
}
public ThreadProxy(Runnable target) {
this.target = target;
}
public void start() {
start0();//这个方法时真正实现多线程方法
}
public void start0() {
run();
}
}
class Dog implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("小狗汪汪叫..hi" + (++count) + Thread.currentThread().getName());
//休眠1秒
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
if(count == 10){
break;
}
}
}
}14..2.4线程使用应用案例-多线程执行
package com.ming.threaduse;
/**
* @author 明
* @version 1.0
* main线程启动两个子线程
*/
public class Thread03 {
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
class T1 implements Runnable{
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("hello,world" + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 10){
break;
}
}
}
}
class T2 implements Runnable{
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("hi" + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 5){
break;
}
}
}
}
14.3 继承Thread vs 实现Runnable的区别
[*]设计角度:Thread类本身实现Runnable接口,本质无区别,但实现接口更灵活。
[*]适用场景:实现Runnable适合多线程共享资源,且避免单继承限制,推荐优先使用。
[*]案例:售票系统
模拟三个售票窗口售100张票,对比两种方式,分析线程安全等问题(如资源竞争导致超卖,后续需同步机制解决 )。
package com.ming.ticket;import com.hspedu.ticket.SellTicket;/** * @author 明 * @version 1.0 * 使用多线程,模拟三个窗口同时售票100张 */public class SellTIcket { public static void main(String[] args) { //测试// SellTicket01 sellTicket01 = new SellTicket01();// SellTicket01 sellTicket02 = new SellTicket01();// SellTicket01 sellTicket03 = new SellTicket01();//// //这里我们会出现超卖..// sellTicket01.start();//启动售票线程// sellTicket02.start();//启动售票线程// sellTicket03.start();//启动售票线程 System.out.println("===使用实现接口方式来售票====="); SellTicket02 sellTicket02 = new SellTicket02(); new Thread(sellTicket02).start(); new Thread(sellTicket02).start(); new Thread(sellTicket02).start(); }}//使用Thread方式class SellTicket01 extends Thread { private static int ticketNum = 100;//让多个线程共享ticketNum @Override public void run() { while (true){ if (ticketNum
页:
[1]