Java多线程(review)
文章目录
- 线程状态
- 线程方法
- 线程停止
- 线程休眠——sleep
- 网络延时
- 模拟倒计时与打印当前系统时间
- 线程礼让——yield
- 线程强制执行——Join
- 线程状态
- 线程优先级
- 守护线程
- 不安全案例
- 死锁
- Lock锁
线程状态
- 新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。 - 就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。 - 运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。 - 阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种: - 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
- 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
- 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
- 死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
线程方法
方法 | 说明 |
---|---|
public void start() | 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
public void run() | 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。 |
public final void setName(String name) | 改变线程名称,使之与参数 name 相同。 |
public final void setPriority(int priority) | 更改线程的优先级。 |
public final void setDaemon(boolean on) | 将该线程标记为守护线程或用户线程。 |
public final void join(long millisec) | 等待该线程终止的时间最长为 millis 毫秒。 |
public void interrupt() | 中断线程。 |
public final boolean isAlive() | 测试线程是否处于活动状态。 |
上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。
方法 | 描述 |
---|---|
public static void yield() | 暂停当前正在执行的线程对象,并执行其他线程。 |
public static void sleep(long millisec) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
public static boolean holdsLock(Object x) | 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 |
public static Thread currentThread() | 返回对当前正在执行的线程对象的引用。 |
public static void dumpStack() | 将当前线程的堆栈跟踪打印至标准错误流。 |
线程停止
- 建议线程正常停止–>利用次数,不建议死循环
- 建议使用标志位–>设置一个标志位
设置一个公开的方法停止线程,转换标志位 - 不要使用stop或者destory等过时或者JDK不建议使用的方法
package com.zeng.state;
//测试停止线程
//1.建议线程正常停止-->利用次数,不建议死循环
//2。 建议使用标志位-->设置一个标志位
//3. 不要使用stop或者destory等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{//设置一个标志位private boolean flag=true;@Overridepublic void run() {int i=0;while(flag){//当线程flag=false,则终止线程运行System.out.println("run....Thread"+i++);}}//设置一个公开的方法停止线程,转换标志位public void stop() {this.flag = false;}public static void main(String[] args) {TestStop testStop = new TestStop();new Thread(testStop).start();for(int i=0;i<1000;i++){System.out.println("main"+i);if(i==900){testStop.stop();System.out.println("线程停止");}}}
}
线程休眠——sleep
- sleep(时间)指定当前线程阻塞的毫秒数;
- sleep存在异常InterruptedException;
- sleep时间达到后线程进入就绪状态
- sleep可以模拟网络延时,倒计时等。
- 每个对象都有一个锁,sleep不会释放锁。
网络延时
- 模拟网络延时:扩大线程的发生性
package com.zeng.state;import com.zeng.demo01.TestThread03;
//模拟网络延时:扩大线程的发生性
public class TestSleep implements Runnable{//票数private int ticketNums=10;@Overridepublic 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) {TestThread03 ticket = new TestThread03();new Thread(ticket,"小明").start();new Thread(ticket,"老师").start();new Thread(ticket,"黄牛党").start();}
}
模拟倒计时与打印当前系统时间
package com.zeng.state;import java.text.SimpleDateFormat;
import java.util.Date;//模拟倒计时
public class TestSleep02 {public static void main(String[] args) throws InterruptedException {//模拟倒计时(调用静态方法)// tenDown();//打印当前系统时间Date startTime = new Date(System.currentTimeMillis());while(true){try {// Date startTime = new Date(System.currentTimeMillis());Thread.sleep(1000);System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));startTime = new Date(System.currentTimeMillis());//获取当前时间} catch (InterruptedException e) {e.printStackTrace();}}}public static /*加上static可以直接调用(静态方法)*/void tenDown() throws InterruptedException {int num=10;while(true){Thread.sleep(1000);//sleep存在异常,抛出System.out.println(num--);if(num<=0){break;}}}
}
线程礼让——yield
- 礼让线程,让正在执行的线程暂停,但不阻塞
- 将线程状态转为就绪状态
- 让CPU重新调度,礼让不一定成功!
package com.zeng.state;
//测试礼让线程
//礼让不一定成功,全看CPU心情
public class TextYield {public static void main(String[] args) {MyYield myYield = new MyYield();new Thread(myYield,"a").start();new Thread(myYield,"b").start();}
}
class MyYield implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"线程开始执行");Thread.yield();//线程礼让System.out.println(Thread.currentThread().getName()+"线程停止执行");}
}
线程强制执行——Join
- Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
- 可以想象成插队
package com.zeng.state;
//测试join方法 想象为插队
public class TestJoin implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("线程VIP来了"+i);}}public static void main(String[] args) throws InterruptedException {//启动我们的线程TestJoin testJoin = new TestJoin();Thread thread = new Thread(testJoin);thread.start();//主线程for (int i = 0; i < 1000; i++) {if(i==200){thread.join();//插队}System.out.println("main"+i);}}
}
线程状态
线程状态。 线程可以处于以下状态之一:
状态 | 说明 |
---|---|
NEW | 尚未启动的线程处于此状态。 |
RUNNABLE | 在Java虚拟机中执行的线程处于此状态。 |
BLOCKED | 被阻塞等待监视器锁定的线程处于此状态。 |
WAITING | 正在等待另一个线程执行特定动作的线程处于此状态。 |
TIMED_WAITING | 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 |
TERMINATED | 已退出的线程处于此状态。 |
一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。
package com.zeng.state;public class TestState {public static void main(String[] args) {Thread thread=new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("///");});//观察状态Thread.State state = thread.getState();System.out.println(state);//new//观察启动后thread.start();//启动线程state=thread.getState();System.out.println(state);//Runwhile(state!=Thread.State.TERMINATED){try {Thread.sleep(1000);state=thread.getState();System.out.println(state);} catch (InterruptedException e) {e.printStackTrace();}}// thread.start();线程进入死亡状态后,就不能再启动,直接报错}
}
线程优先级
- java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
- 线程的优先级用数字表示,范围从1~10;
- Thread.MIN_PRIORITY=1;
- Thread.MAX_PRIORITY=10;
- Thread.NORM_PRIORITY=5;
- 使用以下方式改变或获取优先级
- getPriority().setPriority(int XXX)
- 优先级的设定建议在start()调度前(先设置优先级,再启动)
- 优先级低只意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看CPU调度
package com.zeng.state;
//测试线程的优先级
public class TestPriority {public static void main(String[] args) {//主线程默认优先级System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());MyPriority myPriority = new MyPriority();Thread t1 = new Thread(myPriority);Thread t2 = new Thread(myPriority);Thread t3 = new Thread(myPriority);Thread t4 = new Thread(myPriority);Thread t5 = new Thread(myPriority);Thread t6 = new Thread(myPriority);//先设置优先级,再启动t1.start();t2.setPriority(1);t2.start();t3.setPriority(4);t3.start();t4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10t4.start();t5.setPriority(5);t5.start();t6.setPriority(7);t6.start();}
}
class MyPriority implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());}
}
守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须保护用户线程执行完毕
- 虚拟机不必等待守护线程执行完毕
- 如,后台记录日志操作,监控内存,垃圾回收等待
package com.zeng.state;
//测试守护线程
//人生只有三万天 上帝守护你
public class TestDaemon {public static void main(String[] args) {God god = new God();You you = new You();Thread thread = new Thread(god);thread.setDaemon(true);//默认false是用户线程,正常的线程都是用户线程。。。thread.start();//上帝守护线程启动new Thread(you).start();}
}
class God implements Runnable{@Overridepublic void run() {while(true){System.out.println("上帝保佑着你");}}
}class You implements Runnable{@Overridepublic void run() {for (int i = 0; i < 30000; i++) {System.out.println("你一生都在开心的活着");}System.out.println("-=====goodbye world");}
}
不安全案例
package com.zeng.syn;
//不安全的买票
//线程不安全,有负数public class TestUnsafeBuyTicket {public static void main(String[] args) {BuyTicket station = new BuyTicket();new Thread(station,"我emo了").start();new Thread(station,"你笑了").start();new Thread(station,"可恶的黄牛").start();}
}class BuyTicket implements Runnable{//票private int ticketNums=10;boolean flag=true;//外部停止方式@Overridepublic void run() {//买票while(flag){try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}//synchronized 同步方法,锁的是thisprivate synchronized void buy() throws InterruptedException {//判断是否有票if(ticketNums<=0){flag=false;return;}//模拟延时Thread.sleep(100);//买票System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);}
}
package com.zeng.syn;import java.util.ArrayList;//线程不安全的集合
public class TestUnsafeList {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();for (int i = 0; i < 10000; i++) {new Thread(()->{synchronized (list){list.add(Thread.currentThread().getName());}}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}
package com.zeng.syn;import java.util.concurrent.CopyOnWriteArrayList;
//测试JUC安全类型的集合
public class TestJUc {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();for (int i = 0; i < 1000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());});}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}
死锁
- 产生死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
package com.zeng.thread;
//死锁:多个线程互相抱着对方的资源,然后形成僵持。
public class DeadLock {public static void main(String[] args) {Makeup s1 = new Makeup(0, "灰姑娘");Makeup s2 = new Makeup(0, "白雪公主");s1.start();s2.start();}
}
//口红
class Lipstick{}//镜子
class Mirror{}
class Makeup extends Thread{//需要的资源只有一份,用static来保证只有一份static Lipstick lipstick=new Lipstick();static Mirror mirror=new Mirror();int choice;//选择String girlName;//使用化妆品的人Makeup(int choice,String girlName){this.choice=choice;this.girlName=girlName;}@Overridepublic void run() {//化妆try {makeup();} catch (InterruptedException e) {e.printStackTrace();}}//化妆,互相持有对方的锁,就是需要拿到对方的资源private void makeup() throws InterruptedException {if(choice==0){synchronized (lipstick){//获得口红的锁System.out.println(this.girlName+"获得口红的锁");Thread.sleep(1000);
// synchronized (mirror){//一秒钟获得镜子
// System.out.println(this.girlName+"获得镜子的锁");
// }}synchronized (mirror){//一秒钟获得镜子System.out.println(this.girlName+"获得镜子的锁");}}else{synchronized (mirror){//一秒钟获得镜子System.out.println(this.girlName+"获得镜子的锁");Thread.sleep(1000);
// synchronized (lipstick){//获得口红的锁
// System.out.println(this.girlName+"获得口红的锁");
// }}synchronized (lipstick){//获得口红的锁System.out.println(this.girlName+"获得口红的锁");}}}
}
Lock锁
- Lock是显式锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放。
- Lock只有代码块锁,synchronized有代码块锁和方法锁
- 使用Lock锁,JVM花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
- 优先使用顺序
- Lock>同步代码块(已经进入方法体,分配了相应资源)>同步方法(在方法体之外)
package com.zeng.thread;import java.util.concurrent.locks.ReentrantLock;public class TestLock {public static void main(String[] args) {TestLock2 testLock2 = new TestLock2();new Thread(testLock2).start();new Thread(testLock2).start();new Thread(testLock2).start();}
}class TestLock2 implements Runnable{int ticketNums=10;//定义Lock锁private final ReentrantLock lock=new ReentrantLock();@Overridepublic void run() {while(true){try {lock.lock();if(ticketNums>0){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(ticketNums--);}else{break;}} finally {//解锁lock.unlock();//如果同步代码有异常,要将unlock()写入finally语句块}}}
}
Java多线程(review)相关推荐
- Java 多线程的基本方式
Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):
- Java多线程读取本地照片为二进制流,并根据系统核数动态确定线程数
Java多线程读取图片内容并返回 1. ExecutorService线程池 2. 效率截图 3. 源码 1. ExecutorService线程池 ExecutorService线程池,并可根据系统 ...
- Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService
一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...
- 【收藏】Java多线程/并发编程大合集
(一).[Java并发编程]并发编程大合集-兰亭风雨 [Java并发编程]实现多线程的两种方法 [Java并发编程]线程的中断 [Java并发编程]正确挂起.恢复.终止线程 [ ...
- 40个Java多线程问题总结
(转) 这篇文章作者写的真是不错 40个问题汇总 1.多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所 ...
- Java多线程编程实战:模拟大量数据同步
背景 最近对于 Java 多线程做了一段时间的学习,笔者一直认为,学习东西就是要应用到实际的业务需求中的.否则要么无法深入理解,要么硬生生地套用技术只是达到炫技的效果. 不过笔者仍旧认为自己对于多线程 ...
- Java多线程学习处理高并发问题
在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...
- Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)
Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...
- java多线程编程01---------基本概念
一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...
- Java多线程的同步机制(synchronized)
一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...
最新文章
- 一个有趣的数学问题:万有覆叠问题
- mysql物理读和逻辑读,SQL Server中STATISTICS IO物理读和逻辑读的误区
- mac下Android studio配置gradle的路径
- 利用推送测试工具,测试推送是否写好
- 域迁移(降级)注意事项
- centos7升级gcc,并安装redis
- Win10系统任务栏无法自动隐藏问题
- 使用docker compose 测试集群网络连接性
- cento7忘记root密码怎么办
- 【python】Python学到什么程度可以面试工作
- 终端服务器超出了最大允许连接数解决办法
- 离散数学 第一章 命题逻辑 1-5重言式与蕴含式
- 聊聊DevOps制品管理-不止是存储制品这么简单
- 99%的手机Root方法都在这里
- C语言 || 递归 || 求第n个人的年龄
- 权威报告发布:细数OKEx OKChain公链那些“五星级”的骚操作
- cocos2dx项目显示窗口大小调整
- java模拟键盘按键
- 【玩转腾讯云】免费搭建你的微信机器人!24小时在线!上云!
- nginx的DR模式
热门文章
- ArcGIS地理坐标系与投影坐标系
- Android之glide加载圆形图片地址异常监听
- Android之解决YouTubePlayerView启动在Android5.0左右的手机出现奔溃问题
- 剑指offer之找到链表里面包含环的入口节点
- Android之解决点击PopupWindow外部不消失并且不穿透事件
- Android之第一次不显示EditText光标
- Andriod之使用极光推送自定义消息打造个性的消息推送效果
- ALTER 简单操作(mysql)
- python人脸识别训练模型生产_深度学习-人脸识别DFACE模型pytorch训练(二)
- 如何在html里加入验证码_如何把crc校验加入到对应的程序里?看高手怎么做