JAVA 多线程(一)初识多线程
多线程的编程支持是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. 为什么要学习多线程? 首先相信各位小伙伴在学习 JavaSE 的时候,肯定写过一些小游戏吧,比如猜数字,关机小程序...但是如果现在要在猜数字小游戏上面加上一个功能,设定20秒没猜中,就判定游戏 ...
- java线程钥匙_Java多线程并发编程/锁的理解
一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...
- Java高级特性增强-多线程
请戳GitHub原文: https://github.com/wangzhiwub... 大数据成神之路系列: 请戳GitHub原文: https://github.com/wangzhiwub... ...
- Java基础篇:多线程
文章目录 1.概念:程序.进程.线程 2.线程的创建和使用 3.线程的生命周期 4.线程的同步 5.线程的通信 6.JDK5.0新增线程创建方法 1.概念:程序.进程.线程 程序(program)是为 ...
- 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)
在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...
- Java核心技术点之多线程2
想大致了解多线程的相关知识的可以先看看这篇文章. Java核心技术点之多线程 线程各个状态的变化. 看下wait import java.util.concurrent.ArrayBlockingQu ...
- java线程 教程_Java多线程系列教程
Java多线程系列教程 多线程是Java中不可避免的一个重要主体.从本章开始,我们将展开对多线程的学习.接下来的内容是对Java多线程内容的讲解,涉及到的内容包括,Object类中的wait(), n ...
- Java 程序中的多线程
在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...
- Java学习手记2——多线程
一.线程的概念 CPU执行程序,就好比一个人在干事情一样,同一个时间你只能做一件事情,但是这样的效率实在是太低了,在你用电脑的时候,听歌就不能浏览网页,看电影就不能下载视频,你想想是不是很蛋疼. 所以 ...
- 并发基础篇(一): Java 并发性和多线程
说在前面 介绍文章之前,先给出一个多线程的思维导图, 后续的文章就根据思维导图来一步一步的分析java多线程的知识. 一.介绍 在过去单 CPU 时代,单任务在一个时间点只能执行单一程序.之后发展到多 ...
最新文章
- Ubuntu中用户名密码和root密码修改
- 【MATLAB统计分析与应用100例】案例006:matlab数据的标准化变换
- signature=18441de5a4bb8df92eb5cf5dcca47d1e,Heroísmo y los medios de comunicación (Capítulo 5A 5B)...
- 俄罗斯方块(C++)
- 博客系统。集成调试平台,支持类结构/jar结构预览、支持方法调试和监听、支持修改类字段(变量、常量、枚举)等
- Java中的网络支持Socket应用
- 实验8.3 C++标准模板库(STL)中的双向队列类(deque)
- backbond Model实现
- Canny边缘检测非极大值抑制法在双立方插值(Bicubic)图像边缘优化
- linux的ioctl函数实现
- mds部署服务器系统,Windows服务器2003年对MDS/IPS-8配置示例的iSCSI主机
- 在linux文件下执行.kjb文件和trans文件
- 华为光伏usb适配器_支持22.5W超级快充无线充电,华为P40手机保护壳深度拆解
- UR机器人双臂开发实例
- file_get_contents 访问 ssl 错误的两种解决方法
- JPEG2000图像压缩算法学习
- 自动驾驶系列(二) - 路径规划五种算法简述及对比
- 威纶通屏幕(HMI)开发进阶教程四:通过PLC控制,使宏指令跳转到不同的窗口
- 低代码可以做什么?以织信informat这个平台为例说说
- 如何使用DDC保管箱