synchronized:
包括synchronized方法和synchronized块。
synchronized方法使用this作为默认的“同步监视器”,而synchronized块则需自行指定。
wait、notify、notifyAll必须在同步方法或块中,否则会抛出异常
Object.wait:
要执行obj.wait,当前线程必须拥有obj的监视器(monitor)
执行后会导致当前线程进入等待,直到其它线程调用obj.notify或obj.notifyAll
执行后当前线程会放弃在obj上的所有同步请求(synchronization claims)
注意只是使当前线程处于等待,但对同步方法/块的占有却释放了,所以其它线程便可以随后访问这个同步方法/块了
Object.notify,Object.notifyAll:
要执行obj.notify、obj.notifyAll,当前线程必须拥有obj的监视器(monitor)
obj.notify会随机唤醒一个等待在obj上的线程,而obj.notifyAll却会唤醒所有等待在obj上的线程
被唤醒的线程不能马上执行,直到当前线程放弃obj的同步锁(The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. ),也就是当前线程离开了同步方法/块后
实战一下吧:创建三个线程(a线程打印字符a,b线程打印字符b,c线程打印字符c),使三个线程协作打印出abcabcabc。
- classPrinterextendsThread{
- privateStringchr;
- privateObjectpre,curr;
- publicPrinter(Objectpre,Objectcurr,Stringchr){
- super();
- this.pre=pre;
- this.curr=curr;
- this.chr=chr;
- }
- @Override
- publicvoidrun(){
- for(inti=0;i<3;i++){
- synchronized(pre){
- synchronized(curr){
- System.out.print(chr);
- curr.notify();
- }
- try{
- pre.wait();
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- }
- System.out.print("\n"+chr+"end");
- }
- }
- publicclassTest{
- publicstaticvoidmain(String[]args)throwsInterruptedException{
- Object
- a=newObject(),
- b=newObject(),
- c=newObject();
- Printer
- printerA=newPrinter(c,a,"a"),
- printerB=newPrinter(a,b,"b"),
- printerC=newPrinter(b,c,"c");
- printerA.start();
- Thread.sleep(2000);
- printerB.start();
- Thread.sleep(2000);
- printerC.start();
- }
- }
这个例子你可能看到过,是的,我也是网上发现的。但是你发现没,最终结果是:
abcabc
aend
bend(未出现)
cend(未出现)
而且程序并没有退出!为什么?
为简化问题,我们不妨把for循环去掉,原理是一样的
- @Override
- publicvoidrun(){
- synchronized(pre){
- synchronized(curr){
- System.out.print(chr);
- curr.notify();
- }
- try{
- pre.wait();
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- System.out.print("\n"+chr+"end");
- }
a线程执行后打印“a”,唤醒等待在a上的线程(此时其实并没有其它线程在a上等待)并在pre.wait处等待
b线程执行后打印“b”,唤醒等待在b上的线程(此时其实并没有其它线程在b上等待)并在pre.wait处等待
c线程执行后打印“c”,唤醒等待在c上的线程并在pre.wait处等待。请注意,等待在c上的线程被唤醒了,因此a线程继续往下执行,打印出“aend”后a线程结束。但问题是b,c线程呢?他们并没有被唤醒,因此它们始终在pre.wait处等待着!
因此我们必须为b,c设置一个出口:当i=2(其实是循环次数-1即3-1=2)的时候不执行pre.wait
- classPrinterextendsThread{
- privateStringchr;
- privateObjectpre,curr;
- publicPrinter(Objectpre,Objectcurr,Stringchr){
- super();
- this.pre=pre;
- this.curr=curr;
- this.chr=chr;
- }
- @Override
- publicvoidrun(){
- for(inti=0;i<3;i++){
- synchronized(pre){
- synchronized(curr){
- System.out.print(chr);
- curr.notify();
- }
- if(i<2){
- try{
- pre.wait();
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- }
- }
- System.out.print("\n"+chr+"end");
- }
- }
- publicclassTest{
- publicstaticvoidmain(String[]args)throwsInterruptedException{
- Object
- a=newObject(),
- b=newObject(),
- c=newObject();
- Printer
- printerA=newPrinter(c,a,"a"),
- printerB=newPrinter(a,b,"b"),
- printerC=newPrinter(b,c,"c");
- printerA.start();
- Thread.sleep(2000);
- printerB.start();
- Thread.sleep(2000);
- printerC.start();
- }
- }
当i=2时跳过pre.wait,程序继续执行。之后i=3,由于此时i已经不满足for循环的要求,所以循环结束,直接执行System.out.print("\n"+chr+"end"),之后线程退出。