多线程的编程支持是Java的第一大操作

有无数的书籍用了整整一本书的笔墨去讲解多线程;

这值得我们用更多的时间和精力去参考去学习;

相比之下我们的一篇博客与之相比显得太渺小和微不足道;

在此只能表达自己一些简单而浅显的认知;

(一)什么是多线程?

在计算机科学中:

进程:操作系统中一个程序的执行周期称为一个进程。

线程:一个程序同时执行多个任务,通常,每一个任务就称为一个线程。

比如:QQ从启动那一刻;就开始了它的进程:

QQ运行时有许多的线程,与别人聊天时;有聊天的线程;

看空间动态时,有显示动态的线程

查看QQ好友时,有显示好友列表的线程;

玩坦白说时,有坦白说的线程

.............

进程与线程的关系与区别:

(1) 每个进程拥有自己的一整套变量;是操作系统中资源分配的最小单位;

线程依托进程存在;多个线程共享进程的资源;是操作系统任务调动的基本单位;

共享变量使得线程之间的通信比进程之间通信更有效、更方便。

(2)  与进程相比,线程更加 轻量级;启动、撤销一个进程的开销比启动、撤销一个线程大得多;

(3)没有进程就没有线程;进程一旦终止;其内部的线程全部撤销

而 多线程 就是一个 进程 中有 多个线程 在运行;

也许你觉得这没有什么;

但是当双十一下单或春运抢票之时;我们总是可以对多线程有更加深刻的认知;

高并发:访问的线程量非常高;

高并发带来的问题:服务器内存不够;无法处理新的请求;这也是许多服务器与网站崩溃的原因

(二)多线程的实现:

(1):继承 Thread 类实现多线程;

   java.lang.Thread是线程操作的核心类;在JDK 1.0就已经提供;

新建一个多线程最简单的方法就是直接继承Thread 类而后覆写类中的 run()  方法   (相当与主方法main ( ) 方法)

将我们想要执行的操作写在 run( ) 方法中;

或者在 run() 方法中调用我们想要的方法;

无论哪种方式实现多线程;线程启动一律调用 Thread 类提供的 start () 方法;

   start()方法: 

(1)此方法会首先检查线程状态是否为0;(线程默认状态为0表示未启动)

一个线程的 start()只能调用一次; 如果线程已经启动再次调用 start ( ) 方法会抛出异常;

(2)start ( ) 方法会调用 start0()方法真正的将线程启动;

(3)JVM 调用 start0() 方法进行资源的分配与系统调度;

准备好资源启动线程后回调 run ( )  方法来执行线程的具体任务;

我们可以参考火车站卖票,创建三个卖票的线程;每一个线程就相当于一个卖票窗口;

他们一起对共同的火车票进行交易处理;

每卖一张票;票数就减1;

class MyThread extends Thread{private int ticket =3;          //总票数public void run(){while(this.ticket>0){System.out.println("剩余票数:"+this.ticket--);      //具体的卖票行为}}
}public class Test_1105{public static void main(String[] args) {MyThread thread1 = new MyThread();     //创建三个卖票线程MyThread thread2 = new MyThread();MyThread thread3 = new MyThread();thread1.start();       //启动三个线程thread2.start();thread3.start();}
}

运行结果:

剩余票数:3
剩余票数:3
剩余票数:3
剩余票数:2
剩余票数:2
剩余票数:1
剩余票数:2
剩余票数:1
剩余票数:1Process finished with exit code 0

在运行结果中我们可看到;虽然在启动三个线程的时候,是有先后顺序的;

但是三个线程在运行的时候,是交替进行的;

这就是多个线程同时运行的一种体现;

而真正的在网上买火车票时,也是多个线程在同时进行的;

(2)实现 Runnable 接口来实现多线程:

(1)java 中的多线程的处理就是一个典型的代理模式;其中的Thread类完成资源调度;

系统分配辅助线程业务;自定义的线程类负责真实的义务实现;

(2)实现Runnable 接口实现多线程程序类可以更好的描述资源共享;

在第一种方法中;

虽然火车票一共只有三张;但是一共卖了9张票;因为这三个线程是各种卖各种的;这显然是不行的;

所以第二种方法中;我们就实现三个线程(三个卖票窗口)共享这3张票;

class MyThread implements Runnable{private int ticlet=3;public void run(){while(this.ticlet>0){System.out.println("剩余票数"+this.ticlet--);}}
}
public class Test_1105{public static void main(String[] args) {MyThread mt=new MyThread();Thread thread1=new Thread(mt);   //创建三个卖票线程Thread thread2=new Thread(mt);Thread thread3=new Thread(mt);thread1.start();        //启动三个线程thread2.start();thread3.start();}
}

在这种方法中;线程的创建与第一种方法有一丢丢的区别;

这是因为毕竟 Thread 类是线程操作的核心类;在这种方法中我们没有继承 Thread 类;

而是实现 Runnable 接口;

于是就要想办法实现这两大巨头的对接;

运行结果:

剩余票数3
剩余票数2
剩余票数1Process finished with exit code 0

由运行结果我们可以看到;这一次实现了共享卖票;票数总数依旧是3;

而没有因为卖票窗口的增加而倍增

(3)Callable <T> 接口实现多线程;   唯一 一个带有返回值的线程实现;

当线程需要返回值时;只能采用Callable接口实现多线程;

在 Callable 接口中;将 run()方法换成了 call() 方法;

取得 Callable 接口 call 方法 的返回值:get ( )  方法

class MyThread implements Callable<String> {private int ticlet=3;public String call() throws Exception{while(this.ticlet>0){System.out.println("剩余票数:"+this.ticlet--);}return "票已经卖完了";         //设置返回值}
}public class Test_1105{public static void main(String[] args) throws ExecutionException, InterruptedException {Callable <String> callable=new MyThread();FutureTask<String> futureTask=new FutureTask<>(callable);Thread thread1=new Thread(futureTask);       //创建三个线程Thread thread2=new Thread(futureTask);Thread thread3=new Thread(futureTask);thread1.start();          //启动三个线程thread2.start();thread3.start();System.out.println(futureTask.get());   //取得返回值}
}

在这种方法中;我们设置了返回值;

并且获取到它;

而在创建线程之前;我们也做了一些与其他的工作;

原因嘛;

还是因为 Thread 类才是线程操作的核心类;在这种方法中我们没有继承 Thread 类;

而是实现 Callable 接口;

而 Callable 接口与于 Thread 类d的关系比较淡薄;

于是就要想更多的办法实现这两大巨头的对接;

运行结果:

剩余票数:3
剩余票数:2
剩余票数:1
票已经卖完了Process finished with exit code 0

成功的实现了卖票活动;并且取得返回值;

(三)多线程常用的操作方法:

(1)线程的命名与取得:

(1)通过构造方法将线程命名;

public Thread ( String name )

public Thread ( Runnable target , String name )

(2) 设置线程名称:

public final synchronized void setName(String name)

(3) 取得线程名称

public final String getName ( )

*****        (4)取得当前正在执行的线程对象   (先取得对象;才能执行其他方法)

public static native Thread currentThread ( )

class MyThread implements Runnable{private int ticlet=3;public void run(){while(this.ticlet>0){//取得当前线程的名字并打印  +  打印剩余票数System.out.println(Thread.currentThread().getName()+"剩余票数"+this.ticlet--);}}
}
public class Test_1105{public static void main(String[] args) {MyThread mt=new MyThread();Thread thread1=new Thread(mt,"线程1");   //创建三个卖票线程Thread thread2=new Thread(mt,"线程2");Thread thread3=new Thread(mt,"线程3");thread1.start();        //启动三个线程thread2.start();thread3.start();}
}

我们在这个实现方式中通过构造方法给线程都取了名字;从此每个线程不再默默无闻;

并且在打印时将线程名字打印出来;让其名垂青史;

线程1 剩余票数3
线程1 剩余票数2
线程2 剩余票数1Process finished with exit code 0

从运行结果我们可以看出;

线程1是一个勤劳能干的线程;一个人就卖了两种票;

虽然线程3一直没有出现;但是其实它也在背后默默的行动;

小总结:

其实线程的启动都是随机的,我们无法得知哪一个线程会前开始卖票;也无法得知哪一个线程最后卖完;

而且程序的每一次运行都会有不同的结果;

(2)线程休眠 :sleep(long millis)----单位为毫秒;  属于本地方法 ( native )

~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~

本地方法:JAM 有时候会调用一些不属于自己的方法;这些方法就叫本地方法;本地方法通常由C语言编写;因为C语言

是一种比较底层的语言,在与机器进行直接对话时具有先天的优势;

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sleep()指的是让线程暂缓执行;等到了预计时间在恢复执行

sleep()会立即交出CPU,让CPU去执行其他任务;

sleep()不会释放对象锁;

(3)线程让步: yield  ( )         属于本地方法;

暂停当前正在执行的线程对象;并执行其他线程;

yield () 会让当前线程交出CPU ;但不一定立即交出;

yield()交出CPU后只能让拥有相同优先级的线程有获取CPU的机会;

yield ()不会释放对象锁;

(4)join() 方法:

等待该线程终止;如果在主线程中调用该方法会让主线程休眠;

让调用该方法的线程先执行完毕后再恢复执行主线程;

t.join()方法只会使主线程进入等待池并等待 t 线程执行完毕后才会被唤醒。

并不影响同一时刻处在运行状态的其他线程。

join ( ) 只是对Object 类 wait()做了一层包装;

(5)线程停止:

多线程的停止有三种方法:

1.设置标记位;可以使线程正常退出;

2.使用 stop 方法使线程强制退出;但是该方法不太安全所以已经被放弃;

3.使用 Thread 类中的 interrupt () 方法可以中断线程;

(四)线程优先级:  (优先级是  1 ~10 之间的一个整数)

线程的优先级是指:优先级越高的线程越有可能先执行;仅仅只是有可能而已;

设置优先级:public final void setPriority  ( int  newPriority )

取得优先级:public final int getPriority ( )

Thread.MAX_PRIORITY = 10;          最高优先级

Thread.NORM_PRIORITY = 5;

Thread.MIN_PRIORITY = 1;             最低优先级

主函数( main())的优先级为5;

线程的继承性:优先级可以继承;

在A线程中启动B线程 ;则B和A是优先级一样;

(五)守护线程

守护线程是一种特殊的线程;它属于一种陪伴线程;简单的说;Java中有两种线程:用户线程 和 陪伴线程;

可以通过 isDaemon() 方法来区别他们;

如果返回 false ;说明该线程是 :用户线程

如果返回 true ;说明该线程是:守护线程;

典型的守护线程是 垃圾回收线程;

只要当前 JVM 进程中存在任何一个非守护线程没有结束;守护线程就会一直工作;

只有当最后一个非守护线程结束时;守护线程才会随着 JVM 一同停止工作;

守护线程所做的工作可以用一句话来形容:哪有什么岁月静好,只不过有线程在为你负重前行;

JAVA 多线程(一)初识多线程相关推荐

  1. 【多线程】初识多线程

    1. 为什么要学习多线程? 首先相信各位小伙伴在学习 JavaSE 的时候,肯定写过一些小游戏吧,比如猜数字,关机小程序...但是如果现在要在猜数字小游戏上面加上一个功能,设定20秒没猜中,就判定游戏 ...

  2. java线程钥匙_Java多线程并发编程/锁的理解

    一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...

  3. Java高级特性增强-多线程

    请戳GitHub原文: https://github.com/wangzhiwub... 大数据成神之路系列: 请戳GitHub原文: https://github.com/wangzhiwub... ...

  4. Java基础篇:多线程

    文章目录 1.概念:程序.进程.线程 2.线程的创建和使用 3.线程的生命周期 4.线程的同步 5.线程的通信 6.JDK5.0新增线程创建方法 1.概念:程序.进程.线程 程序(program)是为 ...

  5. 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)

    在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...

  6. Java核心技术点之多线程2

    想大致了解多线程的相关知识的可以先看看这篇文章. Java核心技术点之多线程 线程各个状态的变化. 看下wait import java.util.concurrent.ArrayBlockingQu ...

  7. java线程 教程_Java多线程系列教程

    Java多线程系列教程 多线程是Java中不可避免的一个重要主体.从本章开始,我们将展开对多线程的学习.接下来的内容是对Java多线程内容的讲解,涉及到的内容包括,Object类中的wait(), n ...

  8. Java 程序中的多线程

    在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...

  9. Java学习手记2——多线程

    一.线程的概念 CPU执行程序,就好比一个人在干事情一样,同一个时间你只能做一件事情,但是这样的效率实在是太低了,在你用电脑的时候,听歌就不能浏览网页,看电影就不能下载视频,你想想是不是很蛋疼. 所以 ...

  10. 并发基础篇(一): Java 并发性和多线程

    说在前面 介绍文章之前,先给出一个多线程的思维导图, 后续的文章就根据思维导图来一步一步的分析java多线程的知识. 一.介绍 在过去单 CPU 时代,单任务在一个时间点只能执行单一程序.之后发展到多 ...

最新文章

  1. Ubuntu中用户名密码和root密码修改
  2. 【MATLAB统计分析与应用100例】案例006:matlab数据的标准化变换
  3. signature=18441de5a4bb8df92eb5cf5dcca47d1e,Heroísmo y los medios de comunicación (Capítulo 5A 5B)...
  4. 俄罗斯方块(C++)
  5. 博客系统。集成调试平台,支持类结构/jar结构预览、支持方法调试和监听、支持修改类字段(变量、常量、枚举)等
  6. Java中的网络支持Socket应用
  7. 实验8.3 C++标准模板库(STL)中的双向队列类(deque)
  8. backbond Model实现
  9. Canny边缘检测非极大值抑制法在双立方插值(Bicubic)图像边缘优化
  10. linux的ioctl函数实现
  11. mds部署服务器系统,Windows服务器2003年对MDS/IPS-8配置示例的iSCSI主机
  12. 在linux文件下执行.kjb文件和trans文件
  13. 华为光伏usb适配器_支持22.5W超级快充无线充电,华为P40手机保护壳深度拆解
  14. UR机器人双臂开发实例
  15. file_get_contents 访问 ssl 错误的两种解决方法
  16. JPEG2000图像压缩算法学习
  17. 自动驾驶系列(二) - 路径规划五种算法简述及对比
  18. 威纶通屏幕(HMI)开发进阶教程四:通过PLC控制,使宏指令跳转到不同的窗口
  19. 低代码可以做什么?以织信informat这个平台为例说说
  20. 如何使用DDC保管箱

热门文章

  1. rsync使用_用统一替换rsync
  2. 淘宝直播零代码弹窗生产方案总结
  3. QT不规则形状的按钮的实现
  4. 多多买菜怎么添加自提点?旭宇同创
  5. 小米10pro使用说明书_小米10pro 初步使用体验
  6. macOs m1(ARM架构)开发软件适配情况
  7. 美容行业小程序的特点
  8. 简版 Swift 5.7 新特性一览
  9. yelp dataset导入Neo4j详解(二)
  10. 三核异构,跨界处理新引擎—君正X2000 的跨界能力