现在的位置: 首页 > 综合 > 正文

多线程—–重点内容记录解析

2018年06月08日 ⁄ 综合 ⁄ 共 3165字 ⁄ 字号 评论关闭

1、抢占式多任务和协作(非抢占)式多任务:

使用抢占式调度的系统给每个可运行的线程一个时间片来处理任务。当这个时间片用完时,操作系统剥夺该线程对资源的占用,使其他线程有机会运行。在选择下一个线程时,操作系统会考虑到线程的优先级。

所有现代的桌面和服务器操作系统都使用抢占式调度但一些小型设备,例如手机,可能会采用协作式调度。在这样的设备中,一个线程只有在调用sleep或yield这样的方法时才会丢失控制权

2、不要调用Thread类或Runnable对象的run方法,直接调用run方法会:

(1)只会在当前线程中执行任务,并不会启动新的线程,正确的做法是调用Thread.start方法,它会创建一个新的线程来执行run方法

(2)立即执行,如果其他的线程正在执行一 半,那么会被迫让出cpu

sleep方法可以跑出一个InterruptedException,当发生InterruptedException异常时,我们的run方法将会退出

3、线程阻塞和中断:(阻塞可以恢复到阻塞的点上继续执行,而中断后该线程不再执行)

(1)阻塞:

当发生以下任何一种情况时,线程就进入被阻塞状态:

线程通过调用sleep方法进入睡眠状态

线程调用一个在I/O上被阻塞的操作

线程试图得到一个锁,而锁正被其他线程持有。

线程在等待某个触发条件,显示锁中的条件对象相关的

调用线程的suspend方法(不过该方法已经被弃用)

(2)中断:线程将在它的run方法返回时终止。在JDK1.0中,还存在一个stop方法,其他线程可以调用它来终止线程。不过这个方法现在已经被弃用了。

尽管现在已经没有强制终止线程的方法了,但是你还是可以用interrupt方法来请求终止一个线程。尽管如此,如果一个线程被阻塞了,它就无法检查中断状态了。这就是产生InterruptedException异常的地方。当在一个被阻塞的线程上调用interrupt方法时,阻塞调用(例如sleep或wait)就会被InterruptedException异常所终止。所以如果你循环调用sleep,就要花点心思检查中断状态并捕获interruptedException异常

(3)线程调度的方法:

sleep()方法:   导致线程阻塞,但是线程不会释放它的“锁标志”

yield()方法:   使得线程放弃当前分得的cpu时间,但是不引起线程阻塞,线程处于可执行状态,随时可能再次分得cpu时间

wait()和notify()方法:可以配套使用,但如果wait()方法有设置了时间,也可以在超出指定时间后自动变成可执行状态。wait()使得线程进入阻塞状态。会放弃它所占有的“锁标志”,从而使得线程所在对象中的其他synchronized数据可被别的线程使用

警告:当sleep方法抛出一个InterruptedException异常时,它同时也会清除中断状态

有两个方法非常类似,interrupted和isInterrupted。interrupted方法是一个静态方法,它检查当前线程是否已被中断。而且调用interrupted方法会清除该线程的中断状态。另一方面,isInterrupted方法是一个实例方法,可以用它来检查是否有线程已经被中断了。调用它不会改变中断状态的值

注意点:

也许你会在很多发布的代码中发现InterruptedException异常被抑制在一个很低的层次上,就像下面:(不要这样做

	void mySubTask(){
		try{
			sleep(delay);
		}
		catch(InterruptedException e){} //Don't ignore!
	}

如果你不能很好地在catch子句中处理异常,那么你还有两个合理的选择:

(1)在catch子句中,调用Thread.currentThread().interrupt() 来设置中断状态。然后调用者可以对其进行测试:

	void mySubTask() {
		try {
			sleep();
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
	}

(2)或者,更好的选择是,标记你的方法将抛出InterruptedException异常,不采用try语句块捕获异常。那么调用者(或者,最终的run方法)就能够捕获该异常。

	void mySubTask() throws InterruptedException {
		sleep();
	}

4、java.lang.Thread中的几个方法区别:

void interrupt()

发送一个中断请求给一个线程。这个线程的中断状态被设为true。如果这个线程当前被一个sleep调用阻塞,那么将抛出一个InterruptedException异常

static boolean interrupted()

检查当前线程(即正在执行该指令的线程)是否已经被中断了。注意,这是一个静态方法。对它的调用会产生副作用,它会将当前线程的中断状态设成false

boolean isInterrupted()

检查一个线程是否已经被终止了。与static interrupted方法不同,这个调用不会改变线程的中断状态

static Thread currentThread()

返回代表当前执行线程的Thread对象

5、锁的可重入性

当一个线程请求其他线程已经占有的锁时,请求线程被阻塞。然而内部锁时可重进入的,因此线程在试图获得它自己占有的锁时,请求会成功。重进入意味着锁的请求时基于“每线程(per-thread)”,而不是基于“每调用(per-invocation)”的。
重进入的实现是通过为锁关联一个请求计数和一个占有它的线程。当计数为0时,认为锁时未被占有的。线程请求一个未被占有的锁时,JVM将记录锁的占有者,并且将请求计数置为1。如果同一个线程再一次请求这个锁,计数将递增;每次占用线程退出同步块,计数器值将递减,知道计数器达到0时,锁被释放。

6、锁测试和超时  

线程在调用lock方法来获得另一个线程所持有的锁,不时地会发生阻塞。

而嗲用tryLock方法试图获得一个锁,如果成功则返回true,否则立即返回false,并且线程可以立即离开去干任何其他事情。tryLock方法还可以设置超时参数,

如myLock.tryLock(100,TimeUnit.MILLISECONDS)获得锁,但是阻塞时间不会超过给定的值;如果成功返回true

tryLock方法使用例子

	if(myLock.tryLock()){
		try{   }
		finally{myLock.unlock();}
	}
	else{
		//do something else
	}

7、为什么要弃用stop和suspend方法

stop方法用来直接终止线程,而suspend方法会阻塞线程直到另一个线程调用resume。stop和suspend方法有一些共同点:都试图专横地控制一个给定线程的行为

stop方法

从JDK1.2开始,这两个方法就被弃用了。stop方法天生就不安全,这个方法终止所有为结束的方法,包括run方法。当一个线程停止时,它会立即释放所有它锁住的对象上的锁。这会导致对象处于不一致的状态。例如,转账过程,在取款之后存款之前便停止了,那么现在银行对象就被破坏了。因为锁已经被释放,这种破损会被那些未停止的线程锁观察到。你应该中断一个线程而不是停止它,被中断的线程会在安全的时候停止

suspend方法

与stop方法不同,suspend方法不会破坏对象。但是,如果你用suspend挂起一个拥有锁的线程,那么锁在恢复之前将不会被释放。如果调用suspend方法的线程试图取得相同的锁,程序就会死锁:被挂起的线程在等待恢复,而挂起它的线程在等待获得锁

【上篇】
【下篇】

抱歉!评论已关闭.