程序是指令和数据的有序集合,本身没有任何运行的含义。是一个静态的概念。

在操作系统中运行的程序就是进程(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表达式的更多相关文章

  1. 第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)

    静态代理  package com.kuang.demo03; //静态代理模式总结 //真实对象和代理对象都要实现同一个接口 //代理对象要代理真实角色 //好处:  //代理对象可以做很多真实对象 ...

  2. 01 语言基础+高级:1-7 异常与多线程_day07 【线程池、Lambda表达式】

    day07[线程池.Lambda表达式] 主要内容 等待与唤醒案例 线程池 Lambda表达式 教学目标 -[ ] 能够理解线程通信概念-[ ] 能够理解等待唤醒机制-[ ] 能够描述Java中线程池 ...

  3. 第三章 Lambda表达式

    第三章 Lambda表达式 3.1 函数式编程思想概述 在数学中,函数就是有输入量.输出量的一套计算方案,也就是“拿什么东西做什么事情”.相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函 ...

  4. Util应用程序框架公共操作类(八):Lambda表达式公共操作类(二)

    前面介绍了查询的基础扩展,下面准备给大家介绍一些有用的查询封装手法,比如对日期范围查询,数值范围查询的封装等,为了支持这些功能,需要增强公共操作类. Lambda表达式公共操作类,我在前面已经简单介绍 ...

  5. 函数式编程--lambda表达式对比匿名内部类

    从前面的整理中我们看出了,Lambda表达式其实是匿名内部类的一种简化,因此它可以部分取代匿名内部类. 1,Lambda表达式与匿名内部类存在如下相同点: 1),Lambda表达式与匿名内部类一样,都 ...

  6. JavaSE Lambda表达式(JDK1.8新特性)

    在前面有一篇写到了Lambda表达式,现在可以给你们介绍什么是Lambda表达式 现在有很多老程序员都不喜欢这个函数式编程思想 主要就一点 : 老程序员习惯了 面向过程 写程序,而Lambda表达式是 ...

  7. Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法

    1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...

  8. Java学习笔记-Lambda表达式

    Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数是接口)的实例 意义 自从Java 8开始,Java支持Lambda表达 ...

  9. Java疯狂讲义笔记——Lambda表达式

    Java8新增的Lambda表达式 [特性]支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例. [组成部分]1,形参列表 ...

  10. Java——Lambda表达式

    一.Lambda表达式入门 我们先来看一段代码:匿名内部类的方式实现参数的传递 interface Command{ public abstract void test(); } public cla ...

随机推荐

  1. ModSecurity的规则

    一.ModSecurity的规则 基本格式 SecRule VARIABLES OPERATOR ACTIONS SecRule:ModSecurity主要的指令,用于创建安全规则. VARIABLE ...

  2. 一个最简单的Dubbo入门框架

    Dubbo背景和简介 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起. 1.单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本 ...

  3. Redis 系统学习目录

    Redis 系统学习目录 1.redis是什么2.redis的作者何许人也3.谁在使用redis4.学会安装redis5.学会启动redis6.使用redis客户端7.redis数据结构 – 简介8. ...

  4. Java注释相关以及IDEA配置相关的注释

    本文章主要包括以下6个内容: 一.注释分类以及javadoc的使用 二.使用Alibaba Java Coding Guidelines规范编码. 三.IDEA配置类注释 四.IDEA配置方法注释 = ...

  5. 如何快速开发基于Winform的应用系统

    在我们实际业务开发中,从头开发一个应用系统,不管是基于BS的前端项目,还是基于Winform的CS应用系统,都是由容易到复杂,逐步演化的一个开发过程,如果我们基于一定基础上,并配合一些配套的开发工具, ...

  6. JDBC的全称是什么?

    Java DataBase Connectivity,java数据库连接

  7. 详细描述一下 Elasticsearch 更新和删除文档的过程?

    1.删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不 能被删除或者改动以展示其变更: 2.磁盘上的每个段都有一个相应的.del 文件.当删除请求发送后,文档并没有真 ...

  8. Netty学习摘记 —— 简单WEB聊天室开发

    本文参考 本篇文章是对<Netty In Action>一书第十二章"WebSocket"的学习摘记,主要内容为开发一个基于广播的WEB聊天室 聊天室工作过程 请求的 ...

  9. ip地址与子网掩码概述

    IP地址: IP地址(Internet Protocol):IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异. IP地址分为五 ...

  10. Issues with position fixed & scroll(移动端 fixed 和 scroll 问题)

    转载请注明英文原文及译文出处 原文地址:Issues with position fixed & scrolling on iOS 原文作者:Remy Sharp译文地址:移动端 fixed ...