不知道怎么回事,先写在word文档上的,但是保存后变的很乱。。
1.锁对象的方法:wait(),notify(),notifyAll()
2.线程的方法:
join(),interrupt(),sleep() ,其中stop(),suspend()由于不安全,已经建议不再使用
3.Wait()方法
释放锁并让自己一直处于等待状态。
看下面的例子:
/**
* Created by
* Date : 2018/7/9 14:46
*/
public class Main {
private final Object flag=new Object();
public static void main(String[] args){
Main m=new Main();
m.test();
}
public void test(){
new Thread(){
public void run(){
System.out.println("执行线程");
try{
flag.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("结束线程");
}
}.start();
}
}
执行的结果:
执行线程
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at threadTest.wait.Main$1.run(Main.java:21)
这儿报异常了。是因为调用wait()方法必须是要锁的对象调用,我们修改如下:
/**
* Created by
* Date : 2018/7/9 14:46
*/
public class Main {
private final Object flag=new Object();
public static void main(String[] args){
Main m=new Main();
m.test();
}
public void test(){
new Thread(){
public void run(){
synchronized(flag){
System.out.println("执行线程");
try{
flag.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("结束线程");
}
}
}.start();
}
}
执行结果:
执行线程
调用wait()方法后,上述代码就会一直等待中,直到调用notify()或者notifyAll()等方法通知正在等待的线程获取锁继续执行。
4.Notify()与notifyAll()方法
要想理解这个方法,我们先要理解两个概念:
- 锁池:有多个线程在竞争锁,其中一个线程A竞争到了锁,那么其它的线程就会进入锁池中,等待线程A释放锁,再次竞争
- 等待池:当线程调用了对象的wait()方法后,该线程就会进入等待池,等待池中的线程不会去竞争锁
当调用notify()方法时,会随机将等待池中的该对象的一个线程移到锁池中再次竞争,当调用notifyAll()方法时,会将等待池中的所有的该对象的线程移到锁池中再次竞争。
看下面的例子:
/**
* Created by
* Date : 2018/7/9 14:46
*/
public class Main {
private final Object flag=new Object();
public static void main(String[] args)throws InterruptedException{
Main m=new Main();
m.test();
TimeUnit.SECONDS.sleep(2);
System.out.println("notify thread");
//通知
m.testNotify();
}
public void test(){
for(int i=1;i<=5;i++){
new Thread(String.valueOf(i)){
public void run(){
synchronized(flag){
System.out.println("线程"+Thread.currentThread().getName()+"执行线程");
try{
flag.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"结束线程");
}
}
}.start();
}
}
public void testNotify(){
synchronized (flag){
flag.notify();
}
}
}
执行结果:
线程2执行线程
线程1执行线程
线程3执行线程
线程5执行线程
线程4执行线程
notify thread
线程2结束线程
同样的,在调用notify()方法时也需要同步对象,它会随机通知一个线程。
如果将程序中的flag.notify()改为flag.notifyAll(),则执行结果为:
线程4执行线程
线程1执行线程
线程5执行线程
线程3执行线程
线程2执行线程
notify thread
线程2结束线程
线程3结束线程
线程5结束线程
线程1结束线程
线程4结束线程
5.Sleep()方法
不释放锁,中断一段时间之后继续执行。
看下面的例子:
/**
* Created by WangZhiXin
* Date : 2018/7/9 14:46
*/
public class Main {
private final Object flag=new Object();
public static void main(String[] args){
Main m=new Main();
m.test();
}
public void test(){
new Thread(){
public void run(){
System.out.println("执行线程");
try{
Thread.sleep(3000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("结束线程");
}
}.start();
}
}
执行的结果:
执行线程
结束线程
当隔了三秒后,程序会继续执行,在此期间不释放锁。
6.Join()方法
可以让线程同步执行。当线程A执行start()后,再执行线程A的join(),可以让其它线程等待直到线程A执行结束。其实它的原理就是用wait()方法,有兴趣的小伙伴可以研究下源码。
看下面的例子:
/**
* Created by
* Date : 2018/7/9 15:35
*/
public class Main {
public static void main(String[] args)throws InterruptedException{
for(int i=1;i<=10;i++){
Thread th=new Thread(String.valueOf(i)){
public void run(){
System.out.println("线程"+Thread.currentThread().getName()+"执行线程");
}
};
th.start();
th.join();
}
}
}
执行结果:
线程1执行线程
线程2执行线程
线程3执行线程
线程4执行线程
线程5执行线程
线程6执行线程
线程7执行线程
线程8执行线程
线程9执行线程
线程10执行线程
如果th.join()在th.start()之前执行,那么也不会达到同步的效果
7.Interrupt()
Interrupt()方法主要用来改变线程的运行状态。当线程处于“阻塞状态”时,调用interrupt()会抛出interruptException异常;当线程处于“运行状态”时,调用interrupt()不会抛出异常,但调用isInterrupted()方法会返回true。
举例如下:
/**
* Created by
* Date : 2018/7/9 18:39
*/
public class Main {
public static void main(String[] args)throws InterruptedException{
Main m=new Main();
Thread aTh=m.running();
Thread oTh=m.over();
TimeUnit.SECONDS.sleep(1);
aTh.interrupt();
oTh.interrupt();
}
public Thread running(){
Thread aTh=new Thread("A"){
public void run(){
while(!Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName()+"线程状态未改变");
}
System.out.println(Thread.currentThread().getName()+"线程状态已改变");
}
};
aTh.start();
return aTh;
}
public Thread over(){
Thread oTh=new Thread("B"){
public void run(){
try{
TimeUnit.SECONDS.sleep(100000000);
}catch (InterruptedException e){
System.out.println(Thread.currentThread().getName()+"线程阻塞,调用interrupt()方法,直接抛异常");
}
}
};
oTh.start();
return oTh;
}
}运行结果:
A线程状态未改变
A线程状态未改变
A线程状态未改变
A线程状态已改变
B线程阻塞,调用interrupt()方法,直接抛异常
通过以上可以看出,B线程被阻塞了,所以可以被中断,并抛出了异常;A线程一直在运行,调用interrupt(),却没抛出异常,仅仅是线程的状态改变了,这儿的A线程其实也可以用boolean变量来代替使用。
综上所述,标准的线程阻塞写法是:
try {
// 1. isInterrupted()保证,只要中断标记为true就终止线程。
while (!Thread.currentThread().isInterrupted()) {
// 执行任务...
}
} catch (InterruptedException ie) {
// 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
}