多线程的创建,并发,静态代理,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 ...
随机推荐
- 使用VS Code编译Marlin固件
参考:https://marlinfw.org/docs/basics/install_platformio_vscode.html 前言 在阅读本文之前,您应该已经阅读了使用 PlatformIO ...
- 通过DP总线实现S7-300/400与SINAMICS S120 通讯
一.DP总线通讯功能概述 S7-300/400与SINAMICS S120 之间通过DP总线可进行周期性及非周期性数据通讯. 使用标准S7功能块SFC14/SFC15,S7-300/400PLC通过P ...
- CF1430F Realistic Gameplay (贪心+DP)
朴素做法暴力DP,O(nk)过不去... 1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 ...
- 【编程教室】PONG - 100行代码写一个弹球游戏
大家好,欢迎来到 Crossin的编程教室 ! 今天跟大家讲一讲:如何做游戏 游戏的主题是弹球游戏<PONG>,它是史上第一款街机游戏.因此选它作为我这个游戏开发系列的第一期主题. 游戏引 ...
- mysql覆盖索引与回表
mysql覆盖索引与回表 Harri2012关注 62019.07.28 11:14:15字数 1,292阅读 77,322 select id,name where name='shenjian' ...
- 简单面试前算法一览java
1.排序 冒泡,快速排序 2.查找 二分查找 3.链表 翻转链表 合并链表 是否有环 b. 快慢指针 public class QuickSort { public static void qui ...
- springboot项目配置类
一.在springboot项目中,如果不进行配置,直接访问静态页面是无法访问的,需要进行配置,springboot舍弃了XML文件的配置方式,这里我们采用开发配置类的方式.新建MvcConfig类,加 ...
- B树、B+树、B*树三者的对比详解
转载至:https://www.2cto.com/database/201805/745822.html 对比 B+树是B树的变体,B*树又是B+树的变体,是一脉相承法治国拉的,不断解决新一阶段的问题 ...
- javax.net.ssl.sslhandshakeException:sun.security.validator.validatorException:PKIX path buildind failed
前段时间开发的一个需求,需要通过图片URL获取图片的base64编码,测试的时候使用的是百度图片的url,测试没有问题,但是发布后测试时报如下错: javax.net.ssl.sslhandshake ...
- 如何确保消息正确地发送至 RabbitMQ? 如何确保消息接收方消费了消息?
发送方确认模式 将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都 会被指派一个唯一的 ID. 一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信 道 ...