java高并发程序设计1-线程停下来(stop,wait,suspend,await,interrupt,join,yield,sleep)的操作

版权声明:转载请注明来源 https://blog.csdn.net/tangyuan_sibal/article/details/88695265

写这一篇是因为这几个操作的使用和场景我也经常会记不住,所以写下这一篇文章来记录以后忘了可以翻一翻

1、第一组:被抛弃的stop,suspend

stop:

如果你查看JDK中的Thread线程提供的stop()方法,可以发现已经被弃用了
在这里插入图片描述
而官方文档对它的说明是:这个方法会立即终止正在运行的线程,不管它处于什么样的状态,这会引起安全的异常。比如这样一个场景,你在对一个数据库进行插入数据操作的时候,突然终止这个线程,释放锁,而锁就是来保证数据一致性的,所以stop()就不要用啦。

suspend/resume

这个也是Thread里面的方法,而且也被抛弃了,原因是
在这里插入图片描述
是因为suspend()执行的时候这个线程会被挂起而不释放任何锁的资源,知道等到这个线程重新调用resume(),这个线程才会重新执行。这怎么行呢,本来加锁就很耗系统性能了,你还拿着资源不放,这成何体统。所以必须弃掉。

第二组:wait/await

wait/notify-notifyall

首先wait这一个并不是Thread的方法而是object的方法,这也意味着everyone can use them,那它是怎么样的一个使用过程呢。
加入线程A中,调用了obj.wait(),那么A线程就会停止执行,转为等待状态,那么要等待到何时才结束呢,等到有其他线程调用obj.notify()/obj.notifyall();注意哦,是别人调用notify,而不是等待线程调用的。而等待的线程是怎么样的一个情况呢,
在这里插入图片描述

如图,调用obj.wait(),则线程会进入一个阻塞的线程队列,(T1,T2,T3,T4,T5),而当有线程调用obj.notify的时候,则会随机挑选一个并将其唤醒,而且这个是一个不公平的过程。而notifyall(),则会把在等待队列中的全部唤醒。

而应该注意的一点是,这一对方法并不是随便任意时候都可以调用的,而是应该在synchronized语句中,目标对象都应该先获得监视器。

await/signal-signlall

这个是condition中的方法,我们前面说到wait是跟synchronized一起用的,而await则是跟reentrantlock一起使用的

public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();

其使用方法跟wait差不多。wait要求线程持有synchronized,而await要求线程持有ReentrantLock

第三组:sleep

Object.wait()和Thread.sleep()方法都可以让线程等待若干时间。而sleep()不可以被唤醒且wait()会释放目标对象的锁,而Thread.sleep()不会释放任何资源。根据文档说明

     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.

调用这个方法的对象会暂时停止你设置的时长,(所以sleep()方法必须有时长的参数),sleep主要是为了暂停当前线程,把cpu片段让出给其他线程,延缓当前线程的执行。但是如果调用sleep方法的线程持有锁,它并不会释放锁。

第四组:interrupt

中断是一种重要的线程协作机制。在前面那一节中我们说了stop()这个被弃用的方法的坏处,就是它会不管不顾的直接停止掉你的线程,那么有没有好的线程退出机制呢,这时候中断这个东西就出现了,几乎在计算机系统中都离不开中断这个词。严格来讲,线程中断并不会让线程立即退出,而是给线程发送一个信号,告知目标现成有人希望你退出,至于目标线程接到通知后如何处理,则会完全由目标线程决定。
这里有三个长得很像的三胞胎:

public void Thread.interrupt() //中断线程
public boolean Thread.isInterrupted() // 判断是否被中断
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态。

下面这个代码对t1进行了中断

	public static void main(String[] args) throws InterruptedException {
		
		Thread t1 = new Thread(){
		
			@Override
			public void run(){
				while(true)
				{
					currentThread().yield();
				}
			}
		};
		t1.start();
		Thread.sleep(2000);
		t1.interrupt();
	}

在这里我们希望对t1这个线程进行中断,但是在t1中并没有中断的处理逻辑,因此,即使t1线程被设置了中断状态,这个中断也不会发生任何作用。如果希望t1在中断后退出,就必须为他增加相应的中断处理代码。

public static void main(String[] args) throws InterruptedException {
		
		Thread t1 = new Thread(){
		
			@Override
			public void run(){
				while(true)
				{
					if(Thread.currentThread().isInterrupted())
					{	
						System.out.println("Interrupted!");
						break;
					}
					
					Thread.yield();
				}
			}
		};
		t1.start();
		Thread.sleep(2000);
		t1.interrupt();
	}
}

第五组 等待线程结束join、谦让线程yield

join

等待线程,当先线程在另外一个线程中调用,表示让另外一个线程等待当前调用join()线程执行完毕

public volatile static int i=0;
	public static class AddThread extends Thread{
		@Override
		public void run(){
			for(i=0;i<1000000;i++);
		}
	}
	public static void main(String[] args) throws InterruptedException {
		AddThread addThread = new AddThread();
		addThread.start();
		addThread.join();
		System.out.println(i);
	}

定义一个线程 addThread来对i进行累加,在主线程main中执行这个线程,如果我们不用join,可能输出的是一个非常小的数,因为主线程main还没等addThread执行完就已经执行了,所以加了join()后主线程main会等待addThread线程执行完毕再执行。此外我们可以看到在文档中
在这里插入图片描述

说明了这个join方法实现的核心代码片段是is.Alive(),它让调用线程在当前线程对象上等待,当线程执行完成后,被等待的线程会在退出前调用notifyAll()通知所有等待的线程执行。而且文档中也提到了一点推荐:不要在应用程序,thread实例上使用类似wait()或者notify()方法。因为这可能会影响系统API的工作,或者被系统API所影响。

yield

这是一个谦让线程,它的意思是当前执行的线程会让出cpu,然后重新回到大部队中进行竞争,这是什么样的一个道理呢,比如班级有一个学习非常牛逼的大佬在一次考试中,它非常快的就把试卷写完了,突然老师看到他怎么那么快,给他一个yield信号,让他重新做,这样他又重新跟同学们一起做了,但这时候大佬有可能就是他做两份卷子的速度比你做一份的还快,也有可能你们做的比较快。它的作用就是我给你机会,看你能不能争得过我。。。。。

对于让线程停下来差不多总结就是这样子了。其中有很多地方都是大概说一下而已,因为有些被抛弃的方法就没必要了解的太深了。

猜你喜欢

转载自blog.csdn.net/tangyuan_sibal/article/details/88695265