一、线程阻塞与唤醒方式1:sleep() 方法
- sleep() 允许 指定以毫秒为单位的一段时间作为参数,
- 它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。
public class JamSleepTest {
public static void main(String[] args) {
Thread mt1 = new JamSleepTest.MyThread();
mt1.start();
}
static class MyThread extends Thread {
public void run() {
try {
System.out.println(Thread.currentThread().getName()+" sleep 2s start.");
Thread.sleep(2000);//睡眠阻塞2s
System.out.println(Thread.currentThread().getName()+" sleep 2s end.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
二、线程阻塞与唤醒方式2:suspend() 和 resume() 方法
- 早期JAVA采用suspend()、resume()对线程进行阻塞与唤醒,但这种方式产生死锁的风险很大,
- 因为线程被挂起以后不会释放锁,可能与其他线程、主线程产生死锁.现在该方法显示已过时。
- 这两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。
public class JamSuspendTest { public static void main(String[] args) { Thread mt1 = new MyThread(); mt1.start(); try { System.out.println(Thread.currentThread().getName()+" sleep 1s start."); Thread.currentThread().sleep(1000); System.out.println(Thread.currentThread().getName()+" sleep 1s end."); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" suspend start."); mt1.suspend(); try { System.out.println(Thread.currentThread().getName()+" sleep 3s start."); Thread.currentThread().sleep(3000); System.out.println(Thread.currentThread().getName()+" sleep 3s end."); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" suspend end."); System.out.println(Thread.currentThread().getName()+" resume start."); mt1.resume(); System.out.println(Thread.currentThread().getName()+" resume end."); } static class MyThread extends Thread { public void run() { try { System.out.println(Thread.currentThread().getName()+" running start..."); System.out.println(Thread.currentThread().getName()+" sleep 2s start..."); Thread.sleep(2000);//睡眠阻塞2s System.out.println(Thread.currentThread().getName()+" sleep 2s end..."); System.out.println(Thread.currentThread().getName()+"running end..."); }catch (Exception e){ e.printStackTrace(); } } } }
三、线程阻塞与唤醒方式3:wait() 和 notify() 方法
- wait、notify形式通过一个object作为信号,object的wait()方法是锁门的动作,notify()、notifyAll()是开门的动作,
- 某一线程一旦关上门后其他线程都将阻塞,直到别的线程打开门。notify()准许阻塞的一个线程通过,notifyAll()允许所有线程通过。
public class JamWaitTest {
public static Object waitObject = new Object();
public static void notifyAllThread() {
System.out.println("notifyAllThread");
synchronized (waitObject) {
waitObject.notifyAll();
}
}
public static void notifyThread() {
System.out.println("notifyThread");
synchronized (waitObject) {
waitObject.notify();
}
}
public static void main(String[] args) {
MyThread tm1 = new MyThread(waitObject);
tm1.setName("tm1");
tm1.start();
MyThread tm2 = new MyThread(waitObject);
tm2.setName("tm2");
tm2.start();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tm1.suspendThread();
tm2.suspendThread();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyThread();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyThread();
}
static class MyThread extends Thread {
public Object waitObject = null;
private boolean isStop = false;
public MyThread(Object waitObject) {
this.waitObject = waitObject;
}
public void run() {
while (true) {
synchronized (waitObject) {
if (isStop) {
System.out.println(Thread.currentThread().getId() + " is stop");
try {
waitObject.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + " is resume");
System.out.println(Thread.currentThread().getId() + " will exit");
throw new RuntimeException(Thread.currentThread().getId() +" exit");
}
}
}
}
public void suspendThread() {
this.isStop = true;
}
}
}
四、线程阻塞与唤醒方式4 join()
- 线程实例的join()方法可以使得一个线程在另一个线程结束后再执行,即也就是说使得当前线程可以阻塞其他线程执行;
- 总结:当主线程碰到join后,其后面的线程就被阻塞,等待前面的执行完后后面的才能执行
public class BlockedJoinTest { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runnable() { public void run() { System.out.println("task1 started"); System.out.println("task1 Sleeping for 2 seconds"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task1 completed"); } }); Thread t2 = new Thread(new Runnable() { public void run() { System.out.println("task2 started"); System.out.println("task2 Sleeping for 2 seconds"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task2 completed"); } }); Thread t3= new Thread(new Runnable() { public void run() { System.out.println("task3 started"); System.out.println("task3 Sleeping for 2 seconds"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task3 completed"); } }); //在t执行完毕后t1执行 t1.start(); t1.join();//看到join 后面线程就被阻塞,等待前面的执行完后才能执行 t2.start(); t3.start(); }
}
```
五、线程阻塞与唤醒方式5:park() 与 unPark()方法
- LockSupport提供的park和unpark方法,提供避免死锁和竞态条件,很好地代替suspend和resume组合。
public class JamParkTest {
public static void main(String[] args) {
MyThread mt = new JamParkTest.MyThread();
mt.setName("mt");
mt.start();
try {
Thread.currentThread().sleep(10);
mt.park();
Thread.currentThread().sleep(3000);
mt.unPark();
Thread.currentThread().sleep(3000);
mt.park();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyThread extends Thread {
private boolean isPark = false;
public void run() {
System.out.println(" Enter Thread running.....");
while (true) {
if (isPark) {
System.out.println("Thread is Park.....");
LockSupport.park();
}
}
}
public void park() {
isPark = true;
}
public void unPark() {
isPark = false;
LockSupport.unpark(this);
System.out.println("Thread is unpark.....");
}
}
}