补墙一——java多线程01

2023-10-10 08:30
文章标签 java 多线程 01 补墙

本文主要是介绍补墙一——java多线程01,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 线程简介

多线程——多任务

操作系统中运行的程序就是进程(progress)。

一个进程可以有多个线程(Thread)。

很多多线程都是模拟出来的,在一个cpu下,在同一个时间点,只能运行一个代码,因为切换的很快,所以有多线程同时执行的错觉。

对于同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。

2. 创建线程

在这里插入图片描述

Thread类(也实现了Runnable接口)
在这里插入图片描述

Runnable接口
在这里插入图片描述

Thread类和Runnable接口。

2.1 继承Thread类、重写run方法

创建线程对象,调用start方法启动线程。

public class CreateThread extends Thread{public void run() {for (int i = 0; i < 20; i++) {System.out.println("###I am seeing code!"+i);}}public static void main(String[] args) {CreateThread test = new CreateThread();test.start();//start方法,使两条线程交替执行
//		test.run();for (int i = 0; i < 2000; i++) {System.out.println("I am studying Threads!"+i );}}}

实战——利用多线程下载图片

/*** 练习Thread,实现多线程下载图片*/
public class Demo1 extends Thread{private String url;private String name;public Demo1(String url, String name) {this.url = url;this.name = name;}@Overridepublic void run() {WebDownloader webDownloader = new WebDownloader();webDownloader.downloader(url,name);System.out.println("下载的文件名"+name);}public static void main(String[] args) {Demo1 demo1 = new Demo1("http://n.sinaimg.cn/translate/63/w950h713/20191128/5ca6-iixntzz9340219.jpg","1.jpg");Demo1 demo2 = new Demo1("http://n.sinaimg.cn/translate/63/w950h713/20191128/5ca6-iixntzz9340219.jpg","2.jpg");Demo1 demo3 = new Demo1("http://n.sinaimg.cn/translate/63/w950h713/20191128/5ca6-iixntzz9340219.jpg","3.jpg");demo1.start();demo2.start();demo3.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方法出现问题");}}}

线程是并发执行的

即图片下载完成的时间是随机的

2.2实现Runnable接口–java单继承方式,推荐使用
  • 创建一个线程是声明一个类实现Runnable接口的其他方式。该类实现run方法。那类的一个实例可以分配,作为一个参数传递Thread时创建,并开始。

  • 下面的代码将创建一个线程并开始运行:

      PrimeRun p = new PrimeRun(143);new Thread(p).start();
    

实现:

public static void main(String[] args) {CreateThread2 test = new CreateThread2();new Thread(test).start();//需要作为一个参数放到Thread的构造器中 start方法,使两条线程交替执行
//		test.run();for (int i = 0; i < 20; i++) {System.out.println("I am studying Threads!"+i );}}//线程执行体public void run() {for (int i = 0; i < 20; i++) {System.out.println("###I am seeing code!"+i);}}

实战二——购买火车票(多个线程操作同一个对象)

//多个线程同时操作一个对象
//买火车票——对象车票
public class Demo3 implements Runnable{//票数int numberTickets = 10;//线程执行代码public void run() {while (true){if (numberTickets<=0){break;}//模拟延时try {Thread.sleep(200);}catch (InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"拿到了票"+numberTickets--);}}public static void main(String[] args) {Demo3 demo3 = new Demo3();//三个人同时抢票new Thread(demo3,"小明").start();new Thread(demo3,"小惠").start();new Thread(demo3,"黄牛党").start();}
}

结果——出现bug,线程冲突

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3vsphcT-1605426609107)(C:\Users\26292\AppData\Roaming\Typora\typora-user-images\image-20201113171403241.png)]

实战三——龟兔赛跑

/*** 模拟龟兔赛跑*/
public class Demo4 implements Runnable{//胜利者private static String winner;//线程实现主体public void run() {//乌龟和兔子的速度不同if (Thread.currentThread().getName().equals("兔子")){for (int i=0;i<=100;i=i+5){//判断比赛是否结束boolean flag = gameOver(i);System.out.println(Thread.currentThread().getName()+"跑了"+(i+1)+"步");if (i>90){try {Thread.sleep(400);} catch (InterruptedException e) {e.printStackTrace();}}if (flag){break;}}}if (Thread.currentThread().getName().equals("乌龟")){for (int i = 0; i < 100; i++) {//判断比赛是否结束boolean flag = gameOver(i+1);System.out.println(Thread.currentThread().getName()+"跑了"+(i+1)+"步");if (flag){break;}}}}//判断游戏是否结束public boolean gameOver(int step){//判断是否由胜利者if (winner!=null){return true;}else {if (step>=100){winner = Thread.currentThread().getName();System.out.println("winner is"+winner);return true;}}return false;}public static void main(String[] args) {Demo4 race = new Demo4();new Thread(race,"兔子").start();new Thread(race,"乌龟").start();}
}
2.3实现Callable接口(了解即可)
@FunctionalInterface
public interface Callable<V>

返回结果的一个任务,并可能抛出异常。用户定义一个不带参数调用 call

Callable接口类似于Runnable,,是专为其实例的类可能被另一个线程执行。然而,Runnable,不返回结果并不能抛出异常。

Executors类包含的实用方法与其他常见的形式转换为Callable类。

public class CreateThread3 implements Callable<Boolean> {//线程的执行体public Boolean call() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+ "得到$"+i);}return true;}public static void main(String[] args) {CreateThread3 c1 = new CreateThread3();CreateThread3 c2 = new CreateThread3();CreateThread3 c3 = new CreateThread3();//1.创建执行服务ExecutorService ser = Executors.newFixedThreadPool(3);//2.提交执行--相当于开启线程Future<Boolean> r1 = ser.submit(c1);Future<Boolean> r2 = ser.submit(c2);
//		Future<Boolean> r3 = ser.submit(c3);//3.获取结果try {boolean rs1 = r1.get();boolean rs2 = r2.get();
//			boolean rs3 = r3.get();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ExecutionException e) {// TODO Auto-generated catch blocke.printStackTrace();}//4.关闭服务ser.shutdownNow();}}

3 静态代理

真实角色:你

代理者:婚庆公司

接口:结婚

3.1 实例
/*** 静态代理模式** 真实对象* 共同接口* 代理对象* 真实对象和代理对象实现同一个接口* 代理对象要代理真实对象* * 好处* 代理对象可以做很多真实对象做不了的事情* 真实对象专注做自己的事情*/
public class StaticProxy {public static void main(String[] args) {new WeddingCompany(new You()).HappyMarry();//            new Thread(Runnable).start();}}//共同接口
interface Marry{void HappyMarry();
}//真实角色
class You implements Marry{@Overridepublic void HappyMarry() {System.out.println("我愿意!");}
}//代理角色
class WeddingCompany implements Marry{private Marry client;public WeddingCompany(Marry client) {this.client = client;}@Overridepublic void HappyMarry() {//代理人System.out.println("准备好会场");client.HappyMarry();System.out.println("收尾款");}
}
3.2 线程中的应用

类Thread也实现了Runnable接口

class Thread implements Runnablenew Thread(Runnable).start();

4 Lamda 表达式

4.1Lamda表达式的优点
new Thread(()->System.out.println("多线程学习!")).start();
  • 避免匿名内部类定义过多
  • 可以使代码更简洁
  • 去掉了一堆没有意义的代码
4.2 函数式接口

一个接口里只有唯一一个抽象方法

例如Runnable,Callable

@FunctionalInterface
public interface Runnable

Runnable接口应该被任何类的实例的目的是通过一个线程执行的实施。类必须定义一个称为 run

此接口旨在为那些希望在它们活动时执行代码的对象提供一个通用的协议。例如,Runnable通过类Thread实施。激活的意思是说一个线程已启动并且尚未停止。

此外,Runnable一类是主动的而不是子类Thread提供手段。一个类实现Runnable可以运行没有子Thread实例化一个Thread实例并将自身作为目标。在大多数情况下,这Runnable接口应该是如果你只打算重写run()方法并没有其他Thread方法。这是重要的因为方法重写,继承类不应该继承除非程序员打算修改或增强类的基本行为。

4.3 应用

菜鸟教程

public class TestLambda {//3.静态内部类static class Like2 implements Ilike{@Overridepublic void lambda() {System.out.println("I like Lambda!静态类");}}public static void main(String[] args) {//4.局部内部类class Like3 implements Ilike{@Overridepublic void lambda() {System.out.println("I like Lambda!局部内部类");}}Ilike i = new Like();i.lambda();i = new Like2();i.lambda();i = new Like3();i.lambda();//5.匿名内部类i = new Ilike() {@Overridepublic void lambda() {System.out.println("I like Lambda!匿名内部类");}};i.lambda();//6.用Lambda表达式i = ()->{System.out.println("I like Lambda!Lambda实现");};i.lambda();}}//1.定义接口
interface Ilike{void lambda();
}//2.实现类
class Like implements Ilike{@Overridepublic void lambda() {System.out.println("I like Lambda!");}
}

5 线程的状态

在这里插入图片描述

public static enum Thread.State
extends Enum<Thread.State>

线程状态。一个线程可以有以下规定:

  • NEW
    线程尚未开始。(刚创建)
  • RUNNABLE
    处于这种状态中的java虚拟机执行的线程。 (start)
  • BLOCKED
    线程阻塞等待监控锁在这个国家。
  • WAITING
    处于这种状态的线程被无限期地等待另一个线程来执行特定的动作。
  • TIMED_WAITING
    处于这种状态的线程正在等待另一个线程上执行一个动作指定的等待时间。(sleep)
  • TERMINATED
    处于这种状态的线程退出。 (线程结束)

一个线程可以在一个给定的时间点上只有一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态。

  • 创建状态:new
  • 就绪状态:
  • 阻塞状态:sleep
  • 运行状态
  • 死亡状态
5.1.如何停止线程

不推荐使用stop和destroy方法

public class Test01 implements Runnable{//1.线程正常停止//2.推荐使用一个标志位//3.尽量不使用stop和destroy方法boolean flag = true;@Overridepublic void run() {int i = 0;while (flag){System.out.println("run.....Thread"+(++i));}}//设置一个公开的方法停止线程public void stop(){this.flag = false;}public static void main(String[] args) {Test01 test01 = new Test01();new Thread(test01).start();for (int i = 0; i < 900000000; i++) {if (i == 88880000){System.out.println("main"+(++i));//调用stop方法,切换标志位,使线程停止test01.stop();}}}}
5.2.线程休眠

sleep方法

  • 线程休眠

  • sleep时间到达后线程进入就绪状态

  • 每个对象都有一个锁,sleep并不会释放锁

  • 模拟网络延时–放大问题的发生性

  • 模拟倒计时

5.2.1购票问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cirs7j1H-1605426609112)(C:\Users\26292\AppData\Roaming\Typora\typora-user-images\image-20201114215132529.png)]

5.2.2 打印倒计时
public class Test3 implements Runnable{int number = 10;//剩余时间@Overridepublic void run() {for (int i=number;i>=0;i--){if (i>0){System.out.println("加油!还剩"+i+"秒");}else {System.out.println("时间到了");}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {Test3 test3 = new Test3();new Thread(test3).start();}
}
5.3 线程礼让

yield方法:让当前正在执行的线程暂停,但不阻塞。

将线程从运行状态转为就绪状态

让cpu重新调度,礼让不一定成功,看cpu心情

class TestYield{public static void main(String[] args) {Test4 test4 = new Test4();new Thread(test4).start();new Thread(test4).start();}}public class Test4 implements Runnable{int index = 0;@Overridepublic void run() {System.out.println(index+"线程开始执行");Thread.yield();System.out.println(index+"线程执行结束");index++;}public static void main(String[] args) {}
}
5.4 线程强制执行

join方法

  • join合并线程,等待此线程执行完成后,再执行其他线程,其他线程阻塞。
  • 可以类比与插队
  • 区别于yield
public class Test5 implements Runnable {public void run() {for (int i = 0; i < 1000; i++) {System.out.println("线程vip来了"+(++i));}}public static void main(String[] args) throws InterruptedException {Test5 test5 = new Test5();//启动线程Thread thread = new Thread(test5);Thread thread2 = new Thread(test5);thread.start();//主线程for (int i = 0; i < 100; i++) {if (i==20){thread.join();//非静态方法,需要对象调用}System.out.println("main"+i);}}
}

6 线程优先级(priority)

设置和获取优先级
public class Test1 {public static void main(String[] args) {System.out.println(Thread.currentThread().getName()+"----->"+Thread.currentThread().getPriority());MyPriority myPriority = new MyPriority();Thread thread1 = new Thread(myPriority,"小明");Thread thread2 = new Thread(myPriority,"小花");Thread thread3 = new Thread(myPriority,"小张");Thread thread4 = new Thread(myPriority,"小李");Thread thread5 = new Thread(myPriority);Thread thread6 = new Thread(myPriority);//先设置优先级,在启动,否则设置无效thread1.start();thread2.setPriority(1);thread2.start();thread3.setPriority(5);thread3.start();thread4.setPriority(Thread.MAX_PRIORITY);thread4.start();}}class MyPriority implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"----->"+Thread.currentThread().getPriority());}
}

优先级高的不一定先执行,只是获得调度的概率变大了!!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64yjbjBG-1605426609113)(C:\Users\26292\AppData\Roaming\Typora\typora-user-images\image-20201115153806571.png)]

性能倒置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3ZJWe9D-1605426609114)(C:\Users\26292\AppData\Roaming\Typora\typora-user-images\image-20201115153935813.png)]

7 守护线程

线程分为用户线程守护线程,虚拟机必须确保用户线程执行完毕。

虚拟机不用等待守护线程执行完毕。

public class Test1 {public static void main(String[] args) {God god = new God();//守护线程People people = new People();Thread thread = new Thread(god);thread.setDaemon(true);//默认为false,都是用户线程Thread thread1 = new Thread(people);thread.start();thread1.start();}
}//上帝--一直存在
class God implements Runnable{@Overridepublic void run() {while (true){System.out.println("上帝保佑着你!");}}
}//人类--有寿命长度
class People implements Runnable{@Overridepublic void run() {for (int i = 0; i < 36500; i++) {System.out.println("你第"+(i+1)+"天都开心的活着。");}System.out.println("-==========================goodbye!world!=====================-");}
}

附录. Thread类的关键方法

currentThread()方法

public static Thread currentThread()

返回当前正在执行的线程对象的引用。

结果

当前执行线程。

sleep()方法
public static void sleep(long millis)throws InterruptedException

当前正在执行的线程休眠(暂停执行)为指定的毫秒数,根据精度和系统定时器和调度的准确性。线程不失去任何监视器的所有权。

  • 参数

    millis -睡在毫秒的时间长度

  • 异常

    IllegalArgumentException -如果 millis值为负

    InterruptedException -如果任何线程中断了当前线程。当前线程的空中断状态被清除时,抛出该异常。

具体的Thread类

这篇关于补墙一——java多线程01的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/179287

相关文章

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

Java CompletableFuture如何实现超时功能

《JavaCompletableFuture如何实现超时功能》:本文主要介绍实现超时功能的基本思路以及CompletableFuture(之后简称CF)是如何通过代码实现超时功能的,需要的... 目录基本思路CompletableFuture 的实现1. 基本实现流程2. 静态条件分析3. 内存泄露 bug

Java中Object类的常用方法小结

《Java中Object类的常用方法小结》JavaObject类是所有类的父类,位于java.lang包中,本文为大家整理了一些Object类的常用方法,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. public boolean equals(Object obj)2. public int ha

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机