synchronized:
包括synchronized方法和synchronized块。
synchronized方法:
synchronized限制static方法的时候,
锁对象为这个类的class变量,相当于XXXClass.class.
synchronized限制非static方法的时候,锁对象为这个类的实例(相当于this).
而synchronized块:自己自行指定锁对象。
wait、notify、notifyAll必须在同步方法或块中,否则会抛出异常
Object.wait:
要执行obj.wait,当前线程必须拥有obj的监视器(monitor)
执行后会导致当前线程进入阻塞等待,直到其它线程调用这个obj的notify或notifyAll
注意只是使当前线程处于等待,但对同步方法/块的占有却释放了,所以其它线程便可以随后访问这个同步方法/块了
Object.notify,Object.notifyAll:
要执行obj.notify、obj.notifyAll,当前线程必须拥有obj的监视器(monitor)
obj.notify会随机唤醒一个等待在obj上的线程,而obj.notifyAll却会唤醒所有等待在obj上的线程
wait会释放占有的锁,notify和notifyAll不会释放占用的锁.如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁
sleep:
sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行
实战一下吧:
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();//主线程中启动另外一个线程
System.out.println("b is start....");
//括号里的b是什么意思,应该很好理解吧
synchronized(b) {
try {
System.out.println("Waiting for b to complete...");
b.wait();//synchronized(b)和下面的 synchronized(this)是同一个对象锁
System.out.println("ThreadB is Completed. Now back to main thread");
}catch (InterruptedException e){}
}
System.out.println("Total is :" + b.total);
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {//主线程调用wait后这里才能进来(wait释放阻塞)
System.out.println("ThreadB is running..");
for (int i=0; i<=100; i++ ) {
total += i;
}
System.out.println("total is " + total);
notify();//通知主线程释放阻塞
}
}
}
运行结果:
b is start....
Waiting for b to complete...
ThreadB is running..
total is 5050
ThreadB is Completed. Now back to main thread
Total is :5050
再看一个例子:
- public class MultiThread {
- /**
- * @param args
- */
- public static void main(String[] args) {
- new Thread(new Thread1()).start();
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- new Thread(new Thread2()).start();
- }
- private static class Thread1 implements Runnable {
- @Override
- public void run() {
- // 由于这里的Thread1和下面的Thread2内部run方法要用同一对象作为监视器,我们这里不能用this,因为在Thread2里面的this和这个Thread1的this不是同一个对象。我们用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时,指向的都是同一个对象。
- synchronized (MultiThread.class) {
- System.out.println("enter thread1...");
- System.out.println("thread1 is waiting");
- try {
- // 释放锁有两种方式,第一种方式是程序自然离开监视器的范围,也就是离开了synchronized关键字管辖的代码范围,另一种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。这里,使用wait方法释放锁。
- MultiThread.class.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("thread1 is going on...");
- System.out.println("thread1 is being over!");
- }
- }
- }
- private static class Thread2 implements Runnable {
- @Override
- public void run() {
- synchronized (MultiThread.class) {
- System.out.println("enter thread2...");
- System.out.println("thread2 notify other thread can release wait status..");
- // 由于notify方法并不释放锁,
- // 即使thread2调用下面的sleep方法休息了10毫秒,但thread1仍然不会执行,因为thread2没有释放锁,所以Thread1无法得不到锁。
- //notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁
- MultiThread.class.notify();
- System.out.println("thread2 is sleeping ten millisecond...");
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("thread2 is going on...");
- System.out.println("thread2 is being over!");
- }
- }
- }
- /**
- * 运行结果:
- * enter thread1...
- thread1 is waiting
- enter thread2...
- thread2 notify other thread can release wait status..
- thread2 is sleeping ten millisecond...
- thread2 is going on...
- thread2 is being over!
- thread1 is going on...
- thread1 is being over!
- */
- }