博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Thread详解
阅读量:6721 次
发布时间:2019-06-25

本文共 3241 字,大约阅读时间需要 10 分钟。

具体可参考:,这里对线程状态的转换及主要函数做一下补充。

一. 线程状态转换图

  注意:

  1. 调用obj.wait()的线程需要先获取obj的monitor,wait()会释放obj的monitor并进入等待态。所以wait()/notify()都要与synchronized联用。详见:

1.1 阻塞与等待的区别

阻塞:当一个线程试图获取对象锁(非java.util.concurrent库中的锁,即synchronized),而该锁被其他线程持有,则该线程进入阻塞状态。它的特点是使用简单,由JVM调度器来决定唤醒自己,而不需要由另一个线程来显式唤醒自己,不响应中断

等待:当一个线程等待另一个线程通知调度器一个条件时,该线程进入等待状态。它的特点是需要等待另一个线程显式地唤醒自己,实现灵活,语义更丰富,可响应中断。例如调用:Object.wait()、Thread.join()以及等待Lock或Condition。

  需要强调的是虽然synchronized和JUC里的Lock都实现锁的功能,但线程进入的状态是不一样的。synchronized会让线程进入阻塞态,而JUC里的Lock是用LockSupport.park()/unpark()来实现阻塞/唤醒的,会让线程进入等待态。但话又说回来,虽然等锁时进入的状态不一样,但被唤醒后又都进入runnable态,从行为效果来看又是一样的。

二. 主要操作 

2.1 start()

新启一个线程执行其run()方法,一个线程只能start一次。主要是通过调用native start0()来实现。

1     public synchronized void start() { 2      //判断是否首次启动 3         if (threadStatus != 0) 4             throw new IllegalThreadStateException(); 5  6         group.add(this); 7  8         boolean started = false; 9         try {10        //启动线程11             start0();12             started = true;13         } finally {14             try {15                 if (!started) {16                     group.threadStartFailed(this);17                 }18             } catch (Throwable ignore) {19                 /* do nothing. If start0 threw a Throwable then20                   it will be passed up the call stack */21             }22         }23     }24 25     private native void start0();

2.2 run()

run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当该线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

2.3 sleep()

sleep方法有两个重载版本:

1 sleep(long millis)     //参数为毫秒2  3 sleep(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。

但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。

2.4 yield()

调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

2.5 join()

join方法有三个重载版本:

1 join()2 join(long millis)     //参数为毫秒3 join(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

join()实际是利用了wait(),只不过它不用等待notify()/notifyAll(),且不受其影响。它结束的条件是:1)等待时间到;2)目标线程已经run完(通过isAlive()来判断)。

1 public final synchronized void join(long millis) throws InterruptedException { 2     long base = System.currentTimeMillis(); 3     long now = 0; 4  5     if (millis < 0) { 6         throw new IllegalArgumentException("timeout value is negative"); 7     } 8      9     //0则需要一直等到目标线程run完10     if (millis == 0) {11         while (isAlive()) {12             wait(0);13         }14     } else {15         //如果目标线程未run完且阻塞时间未到,那么调用线程会一直等待。16         while (isAlive()) {17             long delay = millis - now;18             if (delay <= 0) {19                 break;20             }21             wait(delay);22             now = System.currentTimeMillis() - base;23         }24     }25 }

2.6 interrupt()

此操作会将线程的中断标志位置位。如果线程sleep()处于timed_waiting状态,则还会抛出InterruptException;如果线程在运行态则不会受此影响。

可以通过以下三种方式来判断中断:

1)isInterrupted()

此方法只会读取线程的中断标志位,并不会重置。

2)interrupted()

此方法读取线程的中断标志位,并会重置。

3)throw InterruptException

抛出该异常的同时,会重置中断标志位。

2.7 suspend()/resume()

挂起线程,直到被resume,才会苏醒。

但调用suspend()的线程和调用resume()的线程,可能会因为争锁的问题而发生死锁,所以JDK 7开始已经不推荐使用了。

 

转载于:https://www.cnblogs.com/waterystone/p/4920007.html

你可能感兴趣的文章
junit4使用 (转http://blog.csdn.net/afeilxc/article/details/6218908 )
查看>>
电脑蓝屏--代码0x0000008E
查看>>
mysql主从配置(freebsd+mysql5.5.13)
查看>>
开启win7远程桌面
查看>>
使用fir.im和蒲公英进行测试的一些注意事项
查看>>
我的友情链接
查看>>
Yellow dog
查看>>
Python网络编程之协程
查看>>
趣学Python之弹球游戏第二阶段--向上运动
查看>>
过滤全文验证正则表达式的一个小程序
查看>>
Cacti的spine进程数引起的问题
查看>>
我的友情链接
查看>>
求一份oracle数据库实习、兼职的工作
查看>>
storm集群的监控
查看>>
Connector|OIM向IBM TDS推送账号(LDAP3)
查看>>
Linux例行性工作at,cron,进程管理
查看>>
vim批量添加删除注释的方法
查看>>
小成本对付宽带我世界实现有线/无线同时上网
查看>>
QT TableWidget应用笔记
查看>>
yum安装Apache Web Server后各个文件存放位置
查看>>