等待和通知
线程合作中有许许多多的方法,等待wait和通知notify就是其二。还是顾名思义,等待和通知。查阅资料发现wait和notify方法不再thread类中,而是在object对象中。任何方法的都可以去调用这两个方法。A线程调用object.wait(),A线程则会等待,直到其他线程调用这个对象的notify方法。
final static Object obj = new Object();
public static class t1 extends Thread{
public void run() {
synchronized (obj) {
try {
System.out.println("Object wait "+" "+System.currentTimeMillis());
obj.wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class t2 extends Thread{
public void run() {
synchronized (obj) {
try {
obj.notify();
System.out.println("Object notify"+" "+System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new t1());
Thread t2 = new Thread(new t2());
t1.start();
Thread.sleep(1000);
t2.start();
}
t1线程使object对象执行wait方法,t2线程使object对象执行notify方法。上述代码main方法中的线程执行顺序,先t1等待一秒再t2。在t1线程的同步锁中,wait方法释放当前的锁,让其他等待该锁的线程参与竞争锁的过程,直到某个线程调用的这个锁的notify方法。在调用notify方法时,并不会直接把锁释放了,仅仅只是通知这个对象,等调用notify方法的这线程结束后,可以随机释放一个等待这个对象的锁的队列的其中一个线程,notifyAll是唤醒所有等待这个对象的锁。
挂起和继续执行
public static Object obj = new Object();
public static class t extends Thread{
String name;
t(String name){
this.name = name;
}
public void run() {
synchronized(obj) {
System.out.println(name);
Thread.currentThread().suspend();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new t("t1");
Thread t2 = new t("t2");
t1.start();
Thread.sleep(1000);
t2.start();
t1.resume();
t2.resume();
t1.join();
t2.join();
}
suspend和resume同样也是被废弃的方法,当resume方法因为某些原因,在suspend方法执行前执行,那么就会导致线程的永久挂起,所有关于obj对象的锁都会受到牵连。以上代码可以用wait和notify方法代替。
public static Object obj = new Object();
static boolean k = false;
static float a = 0;
public static class t extends Thread{
String name;
t(String name){
this.name = name;
}
public void suspendThread() {
k = true;
}
public void resumeThread() {
k = false;
synchronized (this) {
this.notify();
}
}
public void run() {
synchronized(this) {
while(k) {
try {
wait();
}catch (Exception e) {
e.printStackTrace();
}
}
synchronized (obj) {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {}
System.out.println(++a);
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
t t1 = new t("t1");
t1.start();
t1.suspendThread();
Thread.sleep(5000);
t1.resumeThread();
}
还是临时变量k,在t1线程执行后调用挂起线程方法,使得k为true,再等待五秒,执行继续执行方法,使k=false,并通知线程清除挂起标志。也就是线程在执行时遇到死循环,并在循环内执行wait方法,等待5秒后的notify通知并使k=false退出死循环,执行代码。
等待线程结束和谦让
线程的协作,这个就跟我们为人处世很相像了。在程序中,可能会有一个线程等待其他线程全部执行结束自己才执行,或者一个无关紧要的线程把自己“让”给优先级高的线程。于是就有join和yeild这么两个方法。join,它会一直阻塞当前线程,直到这个线程执行结束。或者还有个join(long time)的方法,等待这个线程特定的时间,如果目标线程还在执行,就不等了 ,直接执行。
public class thread extends Thread{
static int j = 0;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new thread());
t.start();
//t.join();
System.out.println(j);
}
public void run(){
for (int i = 0; i < 100000; i++)
j++;
}
}
上述代码中,输出结果是0,因为线程还没开始执行就已经把I的值给输出了,如果带上join,则会等待线程t执行结束,这时候输出结果就是100000了。
yiled方法一旦执行,会使这个线程让出cpu时间片,但也会参与资源争夺,由于是完全随机,也有可能让出时间片的下一个点又拿到了时间片。