文章目录
多线程编程
一、线程、进程、多线程、程序概念
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
简单理解下
- 多任务:
eg:一个人边骑车边看电脑
- 多线程:
eg:原来一条路太窄只能走一个人,现拓宽可走三个人
一个进程中可以并发多个线程,每条线程并行执行不同的任务。
进程和程序的区别?
- 进程是系统资源分配的单位;程序是一组有序的指令和数据的集合
- 进程使程序的一次执行,动态的;程序是静态的。离开进程程序也就没有存在的意义
- 进程具有生命周期,是暂时的;程序作为资源可以长期保存
进程和线程的区别?
- 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
- 线程是进程的一个实体,是CPU调度和分派的基本单位。它是比进程更小的能独立运行的基本单位。
- 一个进程可以有多个线程,进程>线程
线程主要要点:
- 线程是系统资源分配的单位
- 是独立的执行路径
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程
- 在一个进程中,若开辟了多个线程,线程的运行由调度器安排调度。调度器CPU与操作系统相关,线程运行的先后顺序不能认为干预
- 对同一份资源操作时,会存在资源抢夺问题,需要并发控制操作
- 主线程main()为系统的入口,用户执行整个程序
- 线程会带来额外开销。eg:CPU调度时间,并发控制时间
二、线程创建的三种方法——重头戏
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
线程创建方式1:继承Thread类
查看JDK文档
Java代码实现步骤:
- 线程子类继承Thread类
- 重写run()方法,写run()方法线程执行体
- 在main()方法中创建子类对象实例,并调用start()方法开启线程
//集成threadCreation;
/**
* 1.用线程类继承Thread类
* 2.重写run()方法,写run()方法的线程执行体
* 3.在主线程main()方法中创建线程类实例并调用start()方法
* 4.观察每次运行的线程顺序
*/
//1.用线程类继承Thread类
public class extendThread extends Thread {
//2.重写run()方法,写run()方法的线程执行体
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("I am a runner "+ i +" !");
}
}
//3.在主线程main()方法中创建线程类实例并调用start()方法
public static void main(String[] args) {
extendThread extendThread = new extendThread();
extendThread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("I am a mainFunction " + i +" !");
}
}
}
两条线程同时交替执行,同一时间只能做一件事情
每次执行的线程顺序都不一样
线程不一定立即执行,需要CPU调度
实例2:线程下载图片
先导包apache.commons.io.FileUtils
【自行百度下载】
//threadCreation;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.net.URL;
public class example_InternetmapDownload extends Thread{
private String url;
private String name;
public example_InternetmapDownload(String url,String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
//线程执行体
webmapDownload download = new webmapDownload();
try {
download.download(url,name);
System.out.println("执行了"+ name+ "文件");
} catch (Exception e) {
e.printStackTrace();
System.out.println("IO出现异常");
}
}
public static void main(String[] args) {
example_InternetmapDownload t1 = new example_InternetmapDownload("https://wx2.sinaimg.cn/large/0024cZx9ly1gngdbd6ffdj60f408in4p02.jpg","01.jpg");
example_InternetmapDownload t2 = new example_InternetmapDownload("https://wx3.sinaimg.cn/large/0024cZx9ly1gngct5epi5j60f408iwmr02.jpg","02.jpg");
example_InternetmapDownload t3 = new example_InternetmapDownload("https://wx2.sinaimg.cn/large/0024cZx9ly1gngccx0kt2j60f408itg602.jpg","03.jpg");
//理想状态下先下载 t1,后下载 t2,最后下载 t3
t1.start();
t2.start();
t3.start();
//执行结果:先下载 t2, 后下载 t3,最后下载 t1
// 执行了02.jpg文件
// 执行了03.jpg文件
// 执行了01.jpg文件
}
}
//建立下载容器类
class webmapDownload{
//创建下载方法
public void download(String url,String name) throws Exception {
//用url定位下载重名新名
FileUtils.copyURLToFile(new URL(url),new File(name));
}
}
线程创建方式2:实现Runnable接口
//threadCreation;
/**
* 实现Runnable接口
* 1.用线程类继承Thread类
* 2.重写run()方法,写run()方法的线程执行体
* 3.在主线程main()方法中创建创建Runnable接口的实现类对象,并创建线程对象代理,通过线程对象开启线程,再调用start()方法
* 4.观察每次运行的线程顺序
*/
public class implRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("I am a runner "+ i +" !");
}
}
public static void main(String[] args) {
//创建Runnable接口的实现类对象
implRunnable runnable = new implRunnable();
//创建线程对象代理,通过线程对象开启线程
new Thread(runnable).start();
for (int i = 0; i < 1000; i++) {
System.out.println("I am a mainFunction " + i +" !");
}
}
}
多线程实例
实例一:买票
//多线程买票;
public class buyTicket implements Runnable{
private int ticketNums = 10;
@Override
public void run() {
while (true){
if (ticketNums <= 0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前执行--->"+Thread.currentThread().getName()+"线程,拿到-->第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
buyTicket ticket = new buyTicket();
new Thread(ticket,"张三").start();
new Thread(ticket,"李四").start();
new Thread(ticket,"小棠").start();
}
}
不同的人同时拿到相同的票数,并发问题出现【并发问题稍后】
实例二:龟兔赛跑
//多线程龟兔赛跑;
/**
* 模拟龟兔赛跑
*/
public class race implements Runnable{
//定义胜利者
private static String winner;
@Override
public void run() {
//模拟兔子睡觉
if (Thread.currentThread().getName().equals("兔子")){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//赛道长i
for (int i = 0; i <= 100; i++) {
//判断比赛有没有结束
boolean flag = isWinner(i);
if (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
/**
* 判断胜利者
* @param i 步数
* @return
*/
public boolean isWinner(int i){
//如果winner不为空,说明比赛结束
if (winner != null){
return true;
}else if (i >= 100){
//winner为空,看哪个步数走的快
winner = Thread.currentThread().getName();
System.out.println("winner is" + winner);
return true;
}
return false;
}
public static void main(String[] args) {
race race = new race();
new Thread(race,"乌龟").start();
new Thread(race,"兔子").start();
}
}
线程创建方式3:实现Callable接口
查看JDK文档
Java代码实现步骤:
- 线程类实现Callable接口,有返回类型
- 重写call()方法,抛出异常
- 在main()方法中创建线程类对象,创建执行服务,提交执行,获得结果,关闭服务
- 运行看结果
实现Callable接口下载图片------>与继承Thread类下载图片代码比较;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* 实现Callable接口
* 1.线程类实现Callable接口,有返回类型
* 2.重写call()方法,抛出异常
* 3.在main()方法中创建线程类对象,
* 3.1创建执行服务
* 3.2提交执行
* 3.3获得结果
* 3.4关闭服务
* 4.运行看结果
*/
public class example_CallableDownload implements Callable {
private String url;
private String name;
public example_CallableDownload(String url,String name){
this.url = url;
this.name = name;
}
@Override
public Object call() throws Exception {
webpictureDownload webpictureDownload = new webpictureDownload();
webpictureDownload.ptDownload(url,name);
System.out.println("执行了" + name + "文件");
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3.在main()方法中创建线程类对象,
example_CallableDownload d1 = new example_CallableDownload("https://wx2.sinaimg.cn/large/0024cZx9ly1gngdbd6ffdj60f408in4p02.jpg","01.jpg");
example_CallableDownload d2 = new example_CallableDownload("https://wx3.sinaimg.cn/large/0024cZx9ly1gngct5epi5j60f408iwmr02.jpg","02.jpg");
example_CallableDownload d3 = new example_CallableDownload("https://wx2.sinaimg.cn/large/0024cZx9ly1gngccx0kt2j60f408itg602.jpg","03.jpg");
// 3.1创建执行服务
ExecutorService service = Executors.newFixedThreadPool(3);
// 3.2提交执行
Future dl1 = service.submit(d1);
Future dl2 = service.submit(d2);
Future dl3 = service.submit(d3);
// 3.3获得结果
Object o1 = dl1.get();
Object o2 = dl2.get();
Object o3 = dl3.get();
// 3.4关闭服务
service.shutdownNow();
}
}
//下载文件类
class webpictureDownload{
//下载方法
public void ptDownload(String url,String name) throws IOException {
//代码与之前一样
FileUtils.copyURLToFile(new URL(url),new File(name));
}
}
3获得结果
Object o1 = dl1.get();
Object o2 = dl2.get();
Object o3 = dl3.get();
// 3.4关闭服务
service.shutdownNow();
}
}
//下载文件类
class webpictureDownload{
//下载方法
public void ptDownload(String url,String name) throws IOException {
//代码与之前一样
FileUtils.copyURLToFile(new URL(url),new File(name));
}
}