没有可以强制线程终止的方法,但是interrupt方法可以请求终止线程的运行,当一个线程去调用interrupt方法的时候,这个线程的中断状态会被置位,这是每一个线程都有的一个boolean标志。Thread.currentThread.isInterrupted()方法可以去查询到当前线程的中断状态。但是如果当前线程被阻塞了(调用了wait或者sleep方法),再调用interrupt方法去请求中断,这个时候会报出InterruptedException异常,这个时候可以去捕获这个异常从而进行结束线程的操作。
如果线程已经处于中断状态,再次调用sleep或者wait方法,将会清除中断状态,并且抛出InterruptedException异常。
线程的几个阶段图:
当一个线程进入同步代码块(synchronized),尝试获取类锁或者对象锁,但是该锁被其他线程持有,该线程就会进入阻塞状态。
当一个线程等待另外的线程来通知调度器,自己就会进入等待状态。比如调用了在A线程中调用B.join方法,A线程就会等待B执行完,然后才会继续执行下去;或者是调用了A.wait(),等待B线程或者其他线程调用notify()方法或者notifyAll来唤醒A线程。也或者是等待Java.util.concurrent库中的lock和Condition时,也会进入等待状态。
有些方法是带时间参数的,比如Thread.sleep(long millis),Thread.sleep(long millis,int nanos),Object.wait(long timeout),Object.wait(long timeout,int nanos),Lock.tryLock(long time, TimeUnit unit),Condition.await(ong time, TimeUnit unit),在等待时长没超过指定时长的时候,会一直保持计时等待的状态,直到超时或者获取到锁,
好像计时等待和等待都可以归类于阻塞状态,只不过有些特殊。
常见方法:
- sleep方法会放弃cpu资源,但是不会放弃锁,就是睡着了也会在这个过程持有锁。
- wait方法会放弃cpu资源,也会放弃锁的持有。
- yield让步给同优先级或者高优先级的线程,自身进程会变为可运行状态,但是可能让步之后,再次被操作系统选中获得cpu资源。
- join方法将当前的线程暂停执行,使用join方法的线程先执行,相当于插队。背景可能是主线程需要计算一个东西,让出资源给子线程去计算,主线程进入阻塞状态,等子线程计算结束之后,主线程由阻塞状态变为可运行状态,之后主线程使用这个计算结果继续运行。
锁
java.util.concurrent.locks.ReentrantLock锁比synchronized更加灵活,需要手动的进行加锁和释放锁。
两个都是可重入锁,ReentrantLock在线程获取锁的时候发现锁已经被持有了,判断当前持有线程的锁是不是当前锁,如果是,则允许再次获得锁,并且会进行计数,在释放锁的时候再进行减数计算。
ReentrantLock lock = new ReentrantLock(true);表示创建的是公平锁,不传或者false就是非公平锁,先请求锁的就先获得锁就是公平锁的特性。
条件对象(Condition):一个锁可以有多个条件对象。在线程获得锁之后发现,发现不满足执行程序的条件了,比如:到了售票口但是,票没了。调用ticket.await方法可以阻塞当前线程,并且会放弃锁,此时保持阻塞状态。在条件满足之后并不会主动去解除阻塞状态,通过其他线程的同一个条件对象去调用condition.signalAll()方法,就会解除这个条件对象上的其他线程的阻塞状态,变为可运行的,而且被唤醒的其他线程并不会直接就获取锁,而是仍去尝试获取锁。