文章目录

  • 线程状态
  • 线程方法
  • 线程停止
  • 线程休眠——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() 将当前线程的堆栈跟踪打印至标准错误流。

线程停止

  1. 建议线程正常停止–>利用次数,不建议死循环
  2. 建议使用标志位–>设置一个标志位
    设置一个公开的方法停止线程,转换标志位
  3. 不要使用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)相关推荐

  1. Java 多线程的基本方式

    Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

  2. Java多线程读取本地照片为二进制流,并根据系统核数动态确定线程数

    Java多线程读取图片内容并返回 1. ExecutorService线程池 2. 效率截图 3. 源码 1. ExecutorService线程池 ExecutorService线程池,并可根据系统 ...

  3. Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService

    一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...

  4. 【收藏】Java多线程/并发编程大合集

    (一).[Java并发编程]并发编程大合集-兰亭风雨    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [ ...

  5. 40个Java多线程问题总结

    (转) 这篇文章作者写的真是不错 40个问题汇总 1.多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所 ...

  6. Java多线程编程实战:模拟大量数据同步

    背景 最近对于 Java 多线程做了一段时间的学习,笔者一直认为,学习东西就是要应用到实际的业务需求中的.否则要么无法深入理解,要么硬生生地套用技术只是达到炫技的效果. 不过笔者仍旧认为自己对于多线程 ...

  7. Java多线程学习处理高并发问题

    在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...

  8. Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)

    Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...

  9. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  10. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

最新文章

  1. 一个有趣的数学问题:万有覆叠问题
  2. mysql物理读和逻辑读,SQL Server中STATISTICS IO物理读和逻辑读的误区
  3. mac下Android studio配置gradle的路径
  4. 利用推送测试工具,测试推送是否写好
  5. 域迁移(降级)注意事项
  6. centos7升级gcc,并安装redis
  7. Win10系统任务栏无法自动隐藏问题
  8. 使用docker compose 测试集群网络连接性
  9. cento7忘记root密码怎么办
  10. 【python】Python学到什么程度可以面试工作
  11. 终端服务器超出了最大允许连接数解决办法
  12. 离散数学 第一章 命题逻辑 1-5重言式与蕴含式
  13. 聊聊DevOps制品管理-不止是存储制品这么简单
  14. 99%的手机Root方法都在这里
  15. C语言 || 递归 || 求第n个人的年龄
  16. 权威报告发布:细数OKEx OKChain公链那些“五星级”的骚操作
  17. cocos2dx项目显示窗口大小调整
  18. java模拟键盘按键
  19. 【玩转腾讯云】免费搭建你的微信机器人!24小时在线!上云!
  20. nginx的DR模式

热门文章

  1. ArcGIS地理坐标系与投影坐标系
  2. Android之glide加载圆形图片地址异常监听
  3. Android之解决YouTubePlayerView启动在Android5.0左右的手机出现奔溃问题
  4. 剑指offer之找到链表里面包含环的入口节点
  5. Android之解决点击PopupWindow外部不消失并且不穿透事件
  6. Android之第一次不显示EditText光标
  7. Andriod之使用极光推送自定义消息打造个性的消息推送效果
  8. ALTER 简单操作(mysql)
  9. python人脸识别训练模型生产_深度学习-人脸识别DFACE模型pytorch训练(二)
  10. 如何在html里加入验证码_如何把crc校验加入到对应的程序里?看高手怎么做