多线程的创建,并发,静态代理,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 ... 
随机推荐
- CVE-2017-11882(Office远程代码执行)
			测试环境:win7+kali+office 2007 xp+kali+office 2003 win7 ip:10.10.1.144 xp ip: 10.10.1.126 kali ip 10.10. ... 
- 一条SQL语句执行得很慢的原因有哪些
			说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你"输入URL回车之后,究竟发生了什么"一样,看看你能说出多少了. 之前腾讯 ... 
- Hibernate实体的三种状态是什么?各有什么特点?
			瞬时态(Transient). 持久态(Persistent).脱管态(Detached).处于持久态的对象也称为PO(Persistence Object),瞬时对象和脱管对象也称为VO(Value ... 
- 什么是 Spring Cloud Bus?我们需要它吗?
			考虑以下情况:我们有多个应用程序使用 Spr ng Cloud Config 读取属性,而S ring Cloud Config 从GIT 读取这些属性. 下面的例子中多个员工生产者模块从 Employe ... 
- 面试问题之计算机网络:TCP滑动窗口
			滑动窗口协议是传输层进行流量控制的一种措施,接收方通过通知发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的,并且滑动窗口分为接收窗口和发送窗口.TC ... 
- 简单描述 MySQL 中,索引,主键,唯一索引,联合索引   的区别,对数据库的性能有什么影响(从读写两方面) ?
			索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们 包含着对数据表里所有记录的引用指针. 普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的 ... 
- 什么是可重入锁(ReentrantLock)?
			举例来说明锁的可重入性 public class UnReentrant{ Lock lock = new Lock(); public void outer(){ lock.lock(); inne ... 
- 在 mapper 中如何传递多个参数?
			1.第一种: DAO 层的函数 public UserselectUser(String name,String area); 对应的 xml,#{0}代表接收的是 dao 层中的第一个参数,#{1} ... 
- MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象
			我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ... 
- 3.3V转5V原理图
