多线程概念及多线程开启方式

坦克大战中怎么控制两个坦克,怎么能在玩游戏的同时还配上声音呢?
在这里插入图片描述

进程和线程

  • 进程: 正在执行的程序
  • 线程: 一条独立的执行路径
  • 一个进程可以只有一条线程,也可以有多条线程

什么时候开启多线程

因为CPU在执行程序时每个时间刻度上只会存在一个线程,因此多线程实际上降低了CPU的工作效率,但同时提高了CPU的使用率

  1. 执行某些耗时任务时
  2. 希望某些程序看起来像是在同时执行
  3. 希望完成某个特定在子任务
  4. 防止线程阻塞

CPU的执行原理

原理

真实环境下,CPU能够同时执行多个程序,本质只是在同一个时间刻度上执行一条线程的一条原子性语句,只不过CPU切换执行速度非常快,我们无法察觉以为是同时执行。

并发和并行

并发:在同一个时间段同时执行
并行:在同一个时间刻度上同时执行

同步和异步

同步:并发情况下会出现同步问题
异步:能够同一个时间段能够处理多个任务,例如ajax请求

多线程和多进程的好处

多进程可以提高CPU的使用率
多线程提高了进程的使用率从而提高了CPU的使用率

多线程的启动方式

方式一:继承Thread类

  1. 自定义类MyThread继承Thread类。
  2. MyThread类里面重写run()方法。
  3. 创建线程对象。
  4. 启动线程。

注意:

  1. 启动线程使用的是start()方法而不是run()方法
  2. 线程能不能多次启动
public class ThreadDemo02 {
	public static void main(String[] args) {
		// 3.创建线程对象。
		CopyFileThread cft = new CopyFileThread(new File("ThreadDemo01.java"), new File("thread.txt"));
		// 4.启动线程。
		// cft.run();
		// cft.start();
		
		PrintNumberThread pnt = new PrintNumberThread();
		Thread t = new Thread(pnt);
		
		cft.start();
		t.start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println("main:" + i);
		}
	}
}

class PrintNumberThread implements Runnable {

	// 2.重写run()方法
	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			System.out.println("实现Runnable方式开启子线程: " + i);
		}
	}
	
}

// 1.自定义类MyThread继承Thread类。
class CopyFileThread extends Thread {
	
	private File srcFile;
	private File descFile;
	
	public CopyFileThread() {
		super();
	}
	
	public CopyFileThread(File srcFile, File descFile) {
		super();
		this.srcFile = srcFile;
		this.descFile = descFile;
	}

	// 2.重写run方法
	@Override
	public void run() {
		// 到底写什么? --> 主方法写什么这里就写什么,这里就是和方法的写法很像,用来书写特定任务的代码
		/*
		 * 1.任务参数 (通过线程封装外界传入) File srcFile, File descFile
		 * 2.任务结果 无
		 * 3.具体的任务 拷贝文件
		 */
		copyFile(srcFile, descFile);
//		for (int i = 0; i < 100; i++) {
//			System.out.println("子线程: " + i);
//		}
	}

	public void copyFile(File srcFile, File descFile) {
		try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(descFile))) {
			int len = 0;
			byte[] bys = new byte[1024];
			while ((len = bis.read(bys)) != -1) {
				bos.write(bys, 0, len);
				bos.flush();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public File getSrcFile() {
		return srcFile;
	}

	public void setSrcFile(File srcFile) {
		this.srcFile = srcFile;
	}

	public File getDescFile() {
		return descFile;
	}

	public void setDescFile(File descFile) {
		this.descFile = descFile;
	}

}

方式二:实现Runnable接口

1.自定义类MyRunnable实现Runnable接口
2.重写run()方法
3.创建MyRunnable类的对象
4.创建Thread类的对象,并把步骤3创建的对象作为构造参数传递
5.启动线程
实现接口方式的好处:
可以避免由于Java单继承带来的局限性。适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想。

public class ThreadDemo03 {
	public static void main(String[] args) {
		
		// 3.创建MyRunnable类的对象
		MyRunnable mr = new MyRunnable();
		// 4.创建Thread类的对象,并把步骤3创建的对象作为构造参数传递
		Thread t = new Thread(mr);
		// 5.启动线程
		t.start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println("主线程: " + i);
		}
	}
}

class MyRunnable implements Runnable {

	// 2.重写run()方法
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println("子线程: " + i);
		}
	}
	
}

方式三: 实现Callable方式开启线程

实现Runnable和实现Callable接口的区别
有返回值
可以声明异常
这里的返回值和异常抛出都是给到线程的启动者

public class ThreadDemo04 {
	public static void main(String[] args) {
		FutureTask<Integer> task = new FutureTask<>(new MyCallable(1,100));
		Thread t = new Thread(task);
		t.start();
		
		for (int i = 0; i < 1000; i++) {
			System.out.println("main: " + i);
		}
		
		try {
			Integer value = task.get();
			System.out.println(value);
		} catch (InterruptedException | ExecutionException e) {
			System.out.println("子线程抛出异常给主线程: " + e);
//			e.printStackTrace();
		}
		
		System.out.println("over");
	}
}

/*
 * 计算m~n的和
 */
class MyCallable implements Callable<Integer> {
	
	private Integer m;
	private Integer n;
	
	public MyCallable() {
		super();
	}

	public MyCallable(Integer m, Integer n) {
		super();
		this.m = m;
		this.n = n;
	}

	@Override
	public Integer call() throws Exception {
		int sum = 0;
		for (int i = m; i <= n; i++) {
			System.out.println("Callable: " + i);
			sum += i;
		}
		throw new NullPointerException();
//		return sum;
	}

	public Integer getM() {
		return m;
	}

	public void setM(Integer m) {
		this.m = m;
	}

	public Integer getN() {
		return n;
	}

	public void setN(Integer n) {
		this.n = n;
	}
	
}

方式四: 匿名内部类开启线程

这里实际是有两种内部类方式,分别为第一种和第二种的内部类形式

public class ThreadDemo05 {
	public static void main(String[] args) {
		new Thread();
		
		new Thread().start();
		
		// 方式一继承Thread开启线程
		new Thread() {}.start();
		
		new Thread() {
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println("方式一继承Thread开启线程:" + i);
				}
			}
		}.start();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println("方式二实现Runnable开启线程:" + i);
				}
			}
		}).start();
		
		// 如果一个线程既继承了Thread,同时实现了Runnable接口,那么继承Thread优先
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println("方式二实现Runnable开启线程---:" + i);
				}
			}
		}) {
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println("方式一继承Thread开启线程---:" + i);
				}
			}
		}.start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println("main:" + i);
		}
	}
}

方式五开启线程: Lambda表达式开启线程

Lambda表达式是JDK1.8之后引入
本质就是方便匿名内部类的书写

函数式接口:
只有一个抽象方法的接口就是函数式接口,例如 Runnable
Lambda表达式的语法:

  1. 形参列表: 形式参数允许省略参数类型
  2. 箭头 ->
  3. 方法体: 由大括号包裹,当方法体中只有一条语句,{}可以省略;当一个方法有返回值的时候,如果只是返回一条语句,那么return和{}都可以省略,这个表达式结果自动作为返回值的结果返回
public class ThreadDemo06 {
	public static void main(String[] args) {
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				
//			}
//		}).start(); 
//		
//		new Thread( () -> System.out.println("HelloWorld") ).start();
		
		new Thread( () -> {
			for (int i = 0; i < 100; i++) {
				System.out.println("实现Runnable方式: " + i);
			}
		}).start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println("main: " + i);
		}
	}
	
	
}

@FunctionalInterface
interface Inter {
	void show(int a, int b);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值