java多线程同步一般用的是synchronized关键字,对其他几个函数wait,join,yield用的不多,尤其是join,yield总是很模糊,现在理一理加深印象。
1、wait
wait用于进入对象锁相关的等待池中,执行wait后会释放对象锁和CPU资源,此时其他线程可以访问获取对象锁了。
wait()经常与notify()(唤醒等待池中的任意一个wait对象),notifyAll(唤醒等待池中的所有wait对象)在一起使用。wait(long timeout)和wait(long timeout, int nanos)既可以用notify()、notifyAll唤醒也可以在超时时间后自动唤醒。值得注意的是wait和notify、notifyAll都必须在synchronized代码块中(The current thread must own this object's monitor)。
private static Object mLockObject=new Object();
private static void waitTest() {
System.out.println("主线程运行");
Thread thread=new waitThread();
thread.start();
long startTime=System.currentTimeMillis();
synchronized (mLockObject){
System.out.println("主线程等待");
try {
mLockObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程继续执行,等待耗时:"+(System.currentTimeMillis()-startTime));
}
static class waitThread extends Thread{
@Override
public void run() {
synchronized (mLockObject){
try {
System.out.println("子线程开始sleep");
Thread.sleep(3000);
mLockObject.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
日志打印如下,可以看出子线程执行notifyAll后主线程才会被唤醒并继续执行。
主线程运行
主线程等待
子线程开始sleep
主线程继续执行,等待耗时:3002
2、join
join用于当前线程等待目标线程完成之后再继续执行
private static void joinTest() {
System.out.println("主线程运行");
Thread thread=new joinThread();
thread.start();
long startTime=System.currentTimeMillis();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程继续执行,join耗时:"+(System.currentTimeMillis()-startTime));
}
static class joinThread extends Thread{
@Override
public void run() {
try {
System.out.println("子线程开始sleep");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
日志打印如下,可以看出子线程执行完后,主线程才会继续执行。
主线程运行
子线程开始sleep
主线程继续执行,join耗时:3003
3、yield
yield用于主动让出执行时间给其他已就绪的线程,当前线程从运行状态转为就绪状态,其他线程是否能够优先执行要看各个线程的状态了。
private static void yieldTest() {
yieldThread mThread1=new yieldThread("thread-1");
yieldThread mThread2=new yieldThread("thread-2");
mThread1.start();
mThread2.start();
}
static class yieldThread extends Thread{
public yieldThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.printf("%s------>%d\n",this.getName(),i);
if (i==2) {
Thread.yield();
}
}
}
}
log显示mThread1执行到i=2时让出了执行时间,mThread2开始执行,当mThread2执行i=2时又交给mThread1继续执行
thread-1------>0
thread-1------>1
thread-1------>2
thread-2------>0
thread-2------>1
thread-2------>2
thread-2------>3
thread-2------>4
thread-1------>3
thread-1------>4