线程生命周期
Start
为线程分配必要的资源,初始化线程Runnable
线程创建后,进入就绪状态,此时线程具备了获取cpu时间片的资格
(线程调度器负责分配,线程调度器不受JVM控制,依赖于底册操作系统),只要调度器分配cpu时间片,即可运行。Running 奔跑吧少年
Blocked
因为如下几种原因,产生阻塞,此时,调度器会忽略该线程,不再分配时间片。- wait() (等待notifyAll的唤醒) (Time_Wating状态与Waiting状态的区别在于,可以在指定时间内自行返回 )
- Sleep()
- I/O阻塞(System.in.read(),普通IO不能够Interrupted,详见上一篇文末)
- 对象锁等待
Dead 线程从run()返回(包括中断)
如下,每种阻塞情况的模拟:
class SleepBlocked implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class IOBlocked implements Runnable {
private InputStream in;
public IOBlocked(InputStream is) {
in = is;
}
public void run() {
System.out.println("waiting for read():");
try {
in.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class SynchronizedBlocked implements Runnable {
public synchronized void f() {
while (true) {// never release lock
Thread.yield();
}
}
public SynchronizedBlocked() {
new Thread() {
public void run() {
f();// Lock acquired by this thread
}
}.start();
}
@Override
public void run() {
System.out.println("Trying to call f()");
f();
System.out.println("Exiting synchronizedBlocked.run() ");
}
}
public class Interrupting {
private static ExecutorService exec = Executors.newCachedThreadPool();
static void test(Runnable r) throws InterruptedException {
Future<?> f = exec.submit(r);
TimeUnit.SECONDS.sleep(360);
System.out.println("interrupting" + r.getClass().getName());
f.cancel(true);
System.out.println("interrupt sent to" + r.getClass().getName());
}
public static void main(String[] args) throws InterruptedException {
test(new SleepBlocked());
test(new IOBlocked(System.in));
test(new SynchronizedBlocked());//死锁
// TimeUnit.SECONDS.sleep(3);
System.out.println("aborting with System.exit(0)");
System.exit(0);
}
}
线程状态
- NEW
线程初始化,并未启动(start()) - RUNNABLE
对running与ready的统称 - BLOCKED
线程锁阻塞 - WATING
等待状态,需要等待其他线程做出一些特定动作(唤醒或中断) - TIME_WATING
在指定时间可返回的WATING - TERMINATED
线程执行完毕终止
Daemon线程
支持型线程,在后台运行,当所有的非Daemon线程结束时该程序终止.不考虑Daemon线程).
Thread.setDaemon(true);
死锁
什么是死锁:
TaskA等待TaskB的完成,TaskB等待TaskC的完成,TaskC又等待TaskA的完成,此时产生了等待链,会无止境的阻塞下去。
产生死锁的必备条件:
- 多任务使用的资源至少有一个是不共享的
- 资源不能被抢占
- 至少有一个任务持有一个资源,并且等待另一个任务释放第二个资源。
- 必须存在循环等待链
消除死锁
以上四个条件消除一个即可
哲学家进餐问题(死锁演示)
/**
* 默认哲学家从左到右依次拿起身边的筷子 当一个哲学家调用taken(),想要拿起筷子时: <br/>
* 1.先等待,直到筷子可用(当前持有筷子的哲学家放下筷子) taken=false <br/>
* 2.然后拿起筷子,并置taken=true,表示当前筷子被占用 <br/>
* 3.使用完毕后,调用drop():释放筷子(taken=false),同事通知其他人,其他人中有等待该筷子的
*/
public class Chopstick {
private boolean taken = false;
public synchronized void take() throws InterruptedException {
while (taken) {
wait();
}
taken = true;
}
public synchronized void drop() {
taken = false;
notifyAll();
}
}
public class Philosopher implements Runnable {
private Chopstick left;
private Chopstick right;
private int id;
private int ponder;
private Random rand = new Random(47);
public Philosopher(Chopstick left, Chopstick right, int id, int ponder) {
super();
this.left = left;
this.right = right;
this.id = id;
this.ponder = ponder;
}
private void pause() throws InterruptedException {
if (ponder == 0)
return;
TimeUnit.MILLISECONDS.sleep(rand.nextInt(ponder * 250));
}
/**
*
* 1.take left chopstick <br/>
* 2.take right chopstick <br/>
* 3.eat for a while <br/>
*/
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// the Philosopher becomes hungry
System.out.println(this + " " + "grabbing left" + Thread.currentThread().getName());
left.take();
System.out.println(this + " " + "grabbing right" + Thread.currentThread().getName());
right.take();
System.out.println(this + " " + "eating" + Thread.currentThread().getName());
pause();
left.drop();
right.drop();
}
} catch (Exception e) {
System.out.println(this + " " + "eating via interrupt");
}
}
@Override
public String toString() {
return "Philosopher [id=" + id + "]";
}
}
public class Philosopher implements Runnable {
private Chopstick left;
private Chopstick right;
private int id;
private Random rand = new Random(47);
public Philosopher(Chopstick left, Chopstick right, int id) {
this.left = left;
this.right = right;
this.id = id;
}
/**
* 1.take left chopstick <br/>
* 2.take right chopstick <br/>
* 3.drop the two chopsticks
*/
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// the Philosopher becomes hungry
System.out.println(this + " " + "grabbing left" + Thread.currentThread().getName());
left.take();
System.out.println(this + " " + "grabbing right" + Thread.currentThread().getName());
right.take();
System.out.println(this + " " + "eating" + Thread.currentThread().getName());
left.drop();
right.drop();
}
} catch (Exception e) {
System.out.println(this + " " + "eating via interrupt");
}
}
@Override
public String toString() {
return "Philosopher [id=" + id + "]";
}
}
此代码产生死锁:
public class DeadLockingDiningPhilosophersMine {
public static void main(String[] args) {
int size = 5;
ExecutorService exec = Executors.newCachedThreadPool();
Chopstick[] chopsticks = assmbleChopsticksBySize(size);
for (int i = 0; i < size; i++) {
exec.execute(new Philosopher(chopsticks[i], chopsticks[(i + 1) % size], i));
}
}
private static Chopstick[] assmbleChopsticksBySize(int size) {
Chopstick[] chopsticks = new Chopstick[size];
for (int i = 0; i < size; i++) {
chopsticks[i] = new Chopstick();
}
return chopsticks;
}
}
2016-03-26 17:34:10
"pool-1-thread-1" - Thread t@9
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Native Method)
- waiting on <7e7f8062> (a com.concurrent.newStart.partEight.Chopstick)
at java.lang.Object.wait(Object.java:485)
at com.concurrent.newStart.partEight.Chopstick.take(Chopstick.java:14)
at com.concurrent.newStart.partEight.Philosopher.run(Philosopher.java:48)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
Locked ownable synchronizers:
- locked <4d948ad7> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
"pool-1-thread-2" - Thread t@10
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Native Method)
- waiting on <3f56e5ed> (a com.concurrent.newStart.partEight.Chopstick)
at java.lang.Object.wait(Object.java:485)
at com.concurrent.newStart.partEight.Chopstick.take(Chopstick.java:14)
at com.concurrent.newStart.partEight.Philosopher.run(Philosopher.java:48)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
Locked ownable synchronizers:
- locked <2e596299> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
....所有线程无止境的等下去
消除死锁,我们可以让最后一个消费者(consumer5)从右到左拿筷子,这样就consumer5就会和consumer1抢占chopsticks[0],从而消除了等待链。
如下:
public class DeadlockingDiningPhilosophers {
public static void main(String[] args) throws Exception {
int ponder = 0;
int size = 10;
ExecutorService exec = Executors.newCachedThreadPool();
Chopstick[] sticks = new Chopstick[size];
for (int i = 0; i < size; i++)
sticks[i] = new Chopstick();
for (int i = 0; i < size - 1; i++)
exec.execute(new Philosopher(sticks[i], sticks[(i + 1) % size], i, ponder));
//破坏条件4,消除等待链
exec.execute(new Philosopher(sticks[4], sticks[(3) % size], 4, ponder));
}
}