多线程的创建,并发,静态代理,Lambda表达式
程序是指令和数据的有序集合,本身没有任何运行的含义。是一个静态的概念。
在操作系统中运行的程序就是进程(Process),如:QQ,播放器,游戏等等。
进程是程序的一次执行过程,是一个动态的概念,是系统资源分配的单位。
一个进程可以有多个线程(Thread),如视频中同时听到声音,看图像,看弹幕等等。线程是CPU调度和执行的单位
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。
如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
线程是独立的执行路径。
在程序运行时,即使自己没有创建线程,后台也会有多个线程,如主线程,gc线程。gc:垃圾回收机制。守护线程。
main()为主线程,是系统的入口。
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。
线程会带来额外的开销,如cpu调度时间,并发控制开销。
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。
线程不一定立即执行,由cpu调度安排。
1.方式一 :继承Thread类
步骤:自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程。
public class ThreadDemo extends Thread{ //1继承Thread类
public static void main(String[] args) {
ThreadDemo threadDemoo = new ThreadDemo(); //3.创建线程对象
threadDemoo.start(); //调用start方法,开启该线程
//主线程
for (int i = 0;i<2000;i++){
System.out.println("我在看弹幕"+i);
}
}
@Override
public void run() {
//2.重写run方法。线程体
for (int i = 0;i<2000;i++){
System.out.println("我在听音乐。"+i);
}
}
}
练习:
实现多线程同步下载图片。
引入一个工具类:implementation "commons-io:commons-io:2.7"
为了使用里面的copyURLToFile(new URL(url),new File(name)); ------>将一个网络地址的内容变成文件。
步骤:
(1)创建一个下载器类 WebDownLoader
(2)创建一个多线程类,继承Thread。
代码如下:
package com.java.multithreading; import org.apache.commons.io.FileUtils; import java.io.File;
import java.io.IOException;
import java.net.URL; //练习thread,实现多线程同步下载图片
public class TestThread extends Thread{
private String url;
private String name; //构造器
public TestThread(String url ,String name){
this.url = url;
this.name = name;
} @Override
public void run() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downloader(url,name);
System.out.println("下载了"+name+"文件");
} public static void main(String[] args) {
TestThread testThread01 = new TestThread("https://img2.baidu.com/it/u=450745774,808114680&fm=253&fmt=auto&app=138&f=JPEG?w=370&h=500","xixi01.jpg");
TestThread testThread02 = new TestThread("https://img0.baidu.com/it/u=1145082949,2832027117&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=914","xix02.jpg");
TestThread testThread03 = new TestThread("http://t14.baidu.com/it/u=2571612918,2603191067&fm=224&app=112&f=JPEG?w=500&h=333","xixi03.jpg"); testThread01.start();
testThread02.start();
testThread03.start();
} } //下载器
class WebDownLoader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name)); //将一个网络地址变成文件
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
运行结果如下:

线程是同步执行的,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。
Thread类是实现了Runnable接口的,我们继承Thread类,其实也就是实现了Runnable接口,然后重写了run方法。

通过new ThreadDemo().start();开启多线程, 它执行了Thread的无参构造方法
2.方式二:实现Runnable接口
步骤:自定义线程类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程。
package com.java.multithreading;
public class RunnableDemo implements Runnable{
@Override
public void run() {
//线程体
for (int i = 0;i<200;i++){
System.out.println("我在听音乐。"+i);
}
}
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo(); //创建Runnable接口的实现类对象
Thread thread = new Thread(runnableDemo); //创建线程对象,通过线程对象来开启我们的线程
thread.start(); //开启线程
//可以将上面代码简写为:
new Thread(runnableDemo).start();
; //调用start方法,开启该线程
//主线程
for (int i = 0;i<1000;i++){
System.out.println("我在看弹幕"+i);
}
}
}
练习:
实现多线程同步下载图片。
此处只需将方式一的代码修改两步:
将继承Thread类改为实现Runnable接口。
将new ThreadDemo().start改为RunnableDemo runnableDemo = new RunnableDemo(); new Thread(runnableDemo).start();
引入一个工具类:implementation "commons-io:commons-io:2.7"
为了使用里面的copyURLToFile(new URL(url),new File(name)); ------>将一个网络地址的内容变成文件。
步骤:
(1)创建一个下载器类 WebDownLoader。这里直接用方式一的下载器。
(2)创建一个多线程类,实现Runnable接口。
代码如下:
package com.java.multithreading; import org.apache.commons.io.FileUtils; import java.io.File;
import java.io.IOException;
import java.net.URL; public class TestRunnable implements Runnable{
private String url;
private String name; //构造器
public TestRunnable(String url ,String name){
this.url = url;
this.name = name;
} @Override
public void run() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downloader(url,name);
System.out.println("下载了"+name+"文件");
}
public static void main(String[] args) {
TestRunnable testRunnable01 = new TestRunnable("https://img2.baidu.com/it/u=450745774,808114680&fm=253&fmt=auto&app=138&f=JPEG?w=370&h=500","xixi01.jpg");
TestRunnable testRunnable02 = new TestRunnable("https://img0.baidu.com/it/u=1145082949,2832027117&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=914","xix02.jpg");
TestRunnable testRunnable03 = new TestRunnable("http://t14.baidu.com/it/u=2571612918,2603191067&fm=224&app=112&f=JPEG?w=500&h=333","xixi03.jpg");
// testThread01.start();
// testThread02.start();
// testThread03.start();
new Thread(testRunnable01).start();
new Thread(testRunnable02).start();
new Thread(testRunnable03).start();
}
}
结果如下:

两者比较:
继承Thread类:
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用:避免oop(面向对象编程)单继承局限性
实现Runnable接口:
- 实现接口Runnable具有多线程能力
- 启动线程:new Thread(Runnable接口的实现类对象).start()
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。
3.方式三:实现Callable接口
步骤:
实现Callable接口,需要返回值类型
重写call方法,需要抛出异常
创建目标对象 t1
创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
提交执行:Future<Boolean> result = ser.submit(t1);
获取结果:boolean r1 = result.get();
关闭服务:ser.shutdownNow();
package com.java.multithreading; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class CallableDemo implements Callable<Boolean>{
private String url;
private String name; public CallableDemo(String url,String name){
this.url = url;
this.name = name;
}
@Override
public Boolean call() throws Exception {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downloader(url,name);
System.out.println("下载了文件:"+name);
return true;
} public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableDemo callableDemo1 = new CallableDemo("https://img2.baidu.com/it/u=450745774,808114680&fm=253&fmt=auto&app=138&f=JPEG?w=370&h=500","xixi01.jpg");
CallableDemo callableDemo2 = new CallableDemo("https://img0.baidu.com/it/u=1145082949,2832027117&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=914","xixi02.jpg");
CallableDemo callableDemo3 = new CallableDemo("http://t14.baidu.com/it/u=2571612918,2603191067&fm=224&app=112&f=JPEG?w=500&h=333","xixi03.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(1);
//提交线程
Future<Boolean> result1 = ser.submit(callableDemo1);
Future<Boolean> result2 = ser.submit(callableDemo2);
Future<Boolean> result3 = ser.submit(callableDemo3);
//获取结果
boolean r1 = result1.get();//此处的异常直接抛出
boolean r2 = result2.get();
boolean r3 = result3.get();
//关闭服务
ser.shutdownNow();
}
}
运行结果:

4.初始并发问题
多个线程同时操作同一个对象,如购买过车票。
package com.java.multithreading; public class
//初识并发问题 。多个线程同时操作同一个对象,如购买过车票。线程紊乱,不安全。
ConcurrencyDemo implements Runnable{
private int ticketNums = 5; //总票数
@Override
public void run() {
while (true){
if (ticketNums <= 0){
break;
}
System.out.println(Thread.currentThread().getName()+"---->拿到了第"+ticketNums--+"票"); }
} public static void main(String[] args) {
ConcurrencyDemo concurrencyDemo = new ConcurrencyDemo();
//多条线程操作同一个实现类。即三条线程一起去抢总数为10的火车票。
new Thread(concurrencyDemo,"一号").start();
new Thread(concurrencyDemo,"二号").start();
new Thread(concurrencyDemo,"三号").start();
} }
运行结果如下:

会出现一号将票全部拿完的情况。
现在我们模拟延时看看:
package com.java.multithreading; public class
//初识并发问题 。多个线程同时操作同一个对象,如购买过车票。线程紊乱,不安全。
ConcurrencyDemo implements Runnable{
private int ticketNums = 5; //总票数
@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) {
ConcurrencyDemo concurrencyDemo = new ConcurrencyDemo();
//多条线程操作同一个实现类。即三条线程一起去抢总数为10的火车票。
new Thread(concurrencyDemo,"一号").start();
new Thread(concurrencyDemo,"二号").start();
new Thread(concurrencyDemo,"三号").start();
} }
运行结果如下:

出现了紊乱。此刻的线程就是不安全的。
5.静态代理模式
package com.java.multithreading; //静态代理模式对比Thread
/*
举例:结婚
结婚需要实现结婚的接口。
结婚不必新娘新郎亲自布置现场,可让婚庆公司帮忙
结婚时只需新人到场举行婚礼即可。
注意:真实对象和代理对象都要实现同一个接口
*/ public class StaticProxy {
public static void main(String[] args) {
Groom groom = new Groom();
//WeddingCompany实现了Marry接口,Thread实现Runnable接口;
new WeddingCompany(groom).Wedding();
new Thread(() -> System.out.println("like")).start();
//Thread类是一个代理,代理中间的真实对象,然后调用start方法
}
} //结婚的接口
interface Marry{
void Wedding();//婚礼
} //真实角色,实现结婚接口,目的是参加婚礼
class Groom implements Marry{
@Override
public void Wedding() {
System.out.println("新郎参加婚礼");
}
} //代理角色,实现结婚接口,目的是筹备婚礼
class WeddingCompany implements Marry{
private Marry target; public WeddingCompany(Marry target){
this.target = target;
}
@Override
public void Wedding() {
System.out.println("婚庆公司筹备婚礼");
this.target.Wedding();//然后真实对象来参加婚礼
}
}
6.Lambda表达式
避免匿名内部类过多,其实质属于函数式编程的概念。
函数式接口的定义:
- 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
如Runnable接口:
package java.lang; @FunctionalInterface
public interface Runnable {
void run();
}
- 对于函数式接口,我们可以通过Lamda表达式来创建该接口对象。
推导 lambda表达式:
原始代码:
package com.java.multithreading;
//推导Lamda表达式
public class LambdaDemo {
public static void main(String[] args) {
IStudy iStudy = new IStudy();
iStudy.lambda();
}
} //定义一个函数式接口
interface Study{
void lambda();//在接口里的方法,就是抽象方法
} //实现类
class IStudy implements Study{
@Override
public void lambda() {
System.out.println("我在学习");
}
}
静态内部类
package com.java.multithreading;
//推导Lamda表达式
public class LambdaDemo {
//实现类
static class IStudy implements Study{
@Override
public void lambda() {
System.out.println("我在学习");
}
}
public static void main(String[] args) {
IStudy iStudy = new IStudy();
iStudy.lambda();
}
} //定义一个函数式接口
interface Study{
void lambda();//在接口里的方法,就是抽象方法
}
局部内部类
package com.java.multithreading;
//推导Lamda表达式
public class LambdaDemo { public static void main(String[] args) {
//实现类
class IStudy implements Study{
@Override
public void lambda() {
System.out.println("我在学习");
}
}
IStudy iStudy = new IStudy();
iStudy.lambda();
}
} //定义一个函数式接口
interface Study{
void lambda();//在接口里的方法,就是抽象方法
}
匿名内部类
package com.java.multithreading;
//推导Lamda表达式
public class LambdaDemo { public static void main(String[] args) {
//实现类
Study iStudy = new Study() {
@Override
public void lambda() {
System.out.println("我在学习");
}
};
iStudy.lambda();
}
} //定义一个函数式接口
interface Study{
void lambda();//在接口里的方法,就是抽象方法
}
用lambda简化
package com.java.multithreading;
//推导Lamda表达式
public class LambdaDemo { public static void main(String[] args) {
//实现类
Study iStudy = ()->{
System.out.println("我在学习");
};
iStudy.lambda();
}
} //定义一个函数式接口
interface Study{
void lambda();//在接口里的方法,就是抽象方法
}
说明:非原创,跟着b站狂神敲的
多线程的创建,并发,静态代理,Lambda表达式的更多相关文章
- 第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)
静态代理 package com.kuang.demo03; //静态代理模式总结 //真实对象和代理对象都要实现同一个接口 //代理对象要代理真实角色 //好处: //代理对象可以做很多真实对象 ...
- 01 语言基础+高级:1-7 异常与多线程_day07 【线程池、Lambda表达式】
day07[线程池.Lambda表达式] 主要内容 等待与唤醒案例 线程池 Lambda表达式 教学目标 -[ ] 能够理解线程通信概念-[ ] 能够理解等待唤醒机制-[ ] 能够描述Java中线程池 ...
- 第三章 Lambda表达式
第三章 Lambda表达式 3.1 函数式编程思想概述 在数学中,函数就是有输入量.输出量的一套计算方案,也就是“拿什么东西做什么事情”.相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函 ...
- Util应用程序框架公共操作类(八):Lambda表达式公共操作类(二)
前面介绍了查询的基础扩展,下面准备给大家介绍一些有用的查询封装手法,比如对日期范围查询,数值范围查询的封装等,为了支持这些功能,需要增强公共操作类. Lambda表达式公共操作类,我在前面已经简单介绍 ...
- 函数式编程--lambda表达式对比匿名内部类
从前面的整理中我们看出了,Lambda表达式其实是匿名内部类的一种简化,因此它可以部分取代匿名内部类. 1,Lambda表达式与匿名内部类存在如下相同点: 1),Lambda表达式与匿名内部类一样,都 ...
- JavaSE Lambda表达式(JDK1.8新特性)
在前面有一篇写到了Lambda表达式,现在可以给你们介绍什么是Lambda表达式 现在有很多老程序员都不喜欢这个函数式编程思想 主要就一点 : 老程序员习惯了 面向过程 写程序,而Lambda表达式是 ...
- Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法
1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...
- Java学习笔记-Lambda表达式
Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数是接口)的实例 意义 自从Java 8开始,Java支持Lambda表达 ...
- Java疯狂讲义笔记——Lambda表达式
Java8新增的Lambda表达式 [特性]支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例. [组成部分]1,形参列表 ...
- Java——Lambda表达式
一.Lambda表达式入门 我们先来看一段代码:匿名内部类的方式实现参数的传递 interface Command{ public abstract void test(); } public cla ...
随机推荐
- ModSecurity的规则
一.ModSecurity的规则 基本格式 SecRule VARIABLES OPERATOR ACTIONS SecRule:ModSecurity主要的指令,用于创建安全规则. VARIABLE ...
- 一个最简单的Dubbo入门框架
Dubbo背景和简介 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起. 1.单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本 ...
- Redis 系统学习目录
Redis 系统学习目录 1.redis是什么2.redis的作者何许人也3.谁在使用redis4.学会安装redis5.学会启动redis6.使用redis客户端7.redis数据结构 – 简介8. ...
- Java注释相关以及IDEA配置相关的注释
本文章主要包括以下6个内容: 一.注释分类以及javadoc的使用 二.使用Alibaba Java Coding Guidelines规范编码. 三.IDEA配置类注释 四.IDEA配置方法注释 = ...
- 如何快速开发基于Winform的应用系统
在我们实际业务开发中,从头开发一个应用系统,不管是基于BS的前端项目,还是基于Winform的CS应用系统,都是由容易到复杂,逐步演化的一个开发过程,如果我们基于一定基础上,并配合一些配套的开发工具, ...
- JDBC的全称是什么?
Java DataBase Connectivity,java数据库连接
- 详细描述一下 Elasticsearch 更新和删除文档的过程?
1.删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不 能被删除或者改动以展示其变更: 2.磁盘上的每个段都有一个相应的.del 文件.当删除请求发送后,文档并没有真 ...
- Netty学习摘记 —— 简单WEB聊天室开发
本文参考 本篇文章是对<Netty In Action>一书第十二章"WebSocket"的学习摘记,主要内容为开发一个基于广播的WEB聊天室 聊天室工作过程 请求的 ...
- ip地址与子网掩码概述
IP地址: IP地址(Internet Protocol):IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异. IP地址分为五 ...
- Issues with position fixed & scroll(移动端 fixed 和 scroll 问题)
转载请注明英文原文及译文出处 原文地址:Issues with position fixed & scrolling on iOS 原文作者:Remy Sharp译文地址:移动端 fixed ...