1、synchronized关键字实现原理:
方法块是通过monitorentry和monitorexit去控制,而同步方法则 是依靠方法修饰符上的ACC_SYNCHRONIZED来完成的,
两个方式都是通过获取对象的监控器实现,同时这种情况是排他的,也就是说同一个时间只能有一个线程获取对象扽监控器
2、监控器,对象,同步队列和执行线程的关系
线程进入同步队列,线程状态变为BLOCKED。当访问Object 的前驱(获得了锁的线程)释放了锁,则该释放操作唤醒阻塞在同步队列中的线程,使其重新 尝试对监视器的获取。
2、通知和等待机制
简单的办法是让消费者线程不断地循环检查变量是否符合预期,如下面代码所示,在 while循环中设置不满足的条件,如果条件满足则退出while循环,从而完成消费者的工作。
while (value != desire) { Thread.sleep(1000);
}
doSomething();
1)难以确保及时性。在睡眠时,基本不消耗处理器资源,但是如果睡得过久,就不能及时 发现条件已经变化,也就是及时性难以保证。
2)难以降低开销。如果降低睡眠的时间,比如休眠1毫秒,这样消费者能更加迅速地发现 条件变化,但是却可能消耗更多的处理器资源,造成了无端的浪费。
以上两个问题,看似矛盾难以调和,但是Java通过内置的等待/通知机制能够很好地解决 这个矛盾并实现所需的功能。
2、使用wait()notify () notifyAll()注意的细节
1)使用wait()、notify()和notifyAll()时需要先对调用对象加锁。
2)调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。
3)notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或 notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。(也就是如果别的线程不是放lock锁,那么wait后续的无法继续执行)
4、notify会将等待队列中一个线程放到同步队列,而notifyall是将所有等待的线程进入同步队列,状态有Wait变为Block。
5、wait方法返回的前提是获得调用对象的锁
public class WaitOrNotifyDemo {
private static Object lock = new Object();
private static volatile boolean flag = true;
public static void main(String[] args) {
Thread thread = new Thread(new waitDemo(), "wiatDemo");
thread.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread1 = new Thread(new notifyDemo(), "notifyDemo");
thread1.start();
}
static class waitDemo implements Runnable {
@Override
public void run() {
synchronized (lock) {
while (flag) {
System.out.println(Thread.currentThread() + " flag"
+ flag + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*System.out.println(flag+"flag");
while (flag) {
System.out.println( "flag"
+ flag );
}*/
System.out.println("end " + Thread.currentThread() + " flag"
+ flag + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
static class notifyDemo implements Runnable {
@Override
public void run() {
synchronized (lock) {
System.out.println("start " + Thread.currentThread() + " hold lock. notify @ " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//lock.notifyAll();
}
//再次加锁
synchronized (lock) {
System.out.println("end " + Thread.currentThread() + " hold lock again. sleep @ " +
new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
在图4-3中,WaitThread首先获取了对象的锁,然后调用对象的wait()方法,从而放弃了锁 并进入了对象的等待队列WaitQueue中,进入等待状态。由于WaitThread释放了对象的锁,
NotifyThread随后获取了对象的锁,并调用对象的notify()方法,将WaitThread从WaitQueue移到 SynchronizedQueue中,此时WaitThread的状态变为阻塞状态。NotifyThread释放了锁之后, WaitThread再次获取到锁并从wait()方法返回继续执行。
join 底层调用的wait()
如果是有时间的话那么计算当前时间和如参数时间