java同步和互斥【用具体程序说明】

         所有对象都自动含有单一的锁,也就是所有对象都有且只有唯一的锁,所以当某个任务(线程)访问一个类A中含有sycnhronized的方法是,那么在这个线程从该方法返回之前(也就是该方法在当前线程执行完之前),类A中的其他被该关键字标记的方法在其他的线程中都会被阻塞。
            通俗点说就是,当调用A的含有synchronized的方法是,A会被枷锁,此时A中其他含有synchronized方法只有等到前一个方法调用完毕释放了锁才能被调用

           具体说明见另一篇博客<<java同步和互斥【相关原理】》

        下面看看具体的程序,其中,Timer中的字段num是共享资源

package com.bankht.synchronize;

public class TestSync implements Runnable {
	Timer timer = new Timer();

	public static void main(String[] args) {
		TestSync test = new TestSync();
		Thread t1 = new Thread(test);
		Thread t2 = new Thread(test);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}

	public void run() {
		timer.add(Thread.currentThread().getName());
	}
}

class Timer {
	private static int num = 0;

	public void add(String name) {

		num++;
		try {
			Thread.sleep(1);
		} catch (InterruptedException e) {
		}
		System.out.println(name + ", 你是第" + num + "个使用timer的线程");

	}
}


 

由于没有同步,所以运行结果如下所示 

t1, 你是第2个使用timer的线程

t2, 你是第2个使用timer的线程


也就是说当线程一运行到num++的时候被打线程2打断了,由于java中递增和递减操作均不是原子操作,所以本程序中即使没有调用sleep,也会出现这种被打断的情况

下面看看同步的效果

 public void add(String name) {
        synchronized (this) {//同步
            num++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(name + ", 你是第" + num + "个使用timer的线程");
        }
    }


这样运行结果就会出是正确的

t1, 你是第1个使用timer的线程

t2, 你是第2个使用timer的线程

但是,下面为了说明问题把TestSync里面的run方法改成如下所示

 public void run() {
//       
            time.add(Thread.currentThread().getName());
            try {
                Thread.sleep(1000);//为了显示结果,让其睡眠一秒
            } catch (InterruptedException ex) {
                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
            }
          System.out.println(Thread.currentThread().getName() + "----");
        }


 

那么在此运行就是

t1, 你是第1个使用timer的线程

t2, 你是第2个使用timer的线程

t1--------

t2--------

而不是你所想象的

t1, 你是第1个使用timer的线程
t1----
t2, 你是第2个使用timer的线程
t2----

原因就是在线程t1在睡眠的时候,线程t2切换进来,执行了一次,怎样得到正确的结果呢,下面把TestSync里面的run方法做如下改进就可以得到上面预期的结果

 public void run() {
       synchronized(time){
            time.add(Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {
                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
            }
          System.out.println(Thread.currentThread().getName() + "----");
        }
    }


因为t1先获得time的锁,所以在执行完run里面的同步块之前,即使sleep(),t2也不会执行,因为t2没有获得time的锁,且sleep()操作也不释放锁(这也是和wait的巨大区别)

附录:TestSync.java全部代码

package com.bankht.synchronize;

import java.util.logging.Level;
import java.util.logging.Logger;

public class TestSync implements Runnable {
	Timer timer = new Timer();

	public static void main(String[] args) {
		TestSync test = new TestSync();
		Thread t1 = new Thread(test);
		Thread t2 = new Thread(test);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}

//	public void run() {
//		timer.add(Thread.currentThread().getName());
//	}
	
//	 public void run() {
//		 timer.add(Thread.currentThread().getName());
//            try {
//                Thread.sleep(1000);//为了显示结果,让其睡眠一秒
//            } catch (InterruptedException ex) {
//                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
//            }
//          System.out.println(Thread.currentThread().getName() + "----");
//        }
	
	 public void run() {
	       synchronized(timer){
	            timer.add(Thread.currentThread().getName());
	            try {
	                Thread.sleep(3000);
	            } catch (InterruptedException ex) {
	                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
	            }
	          System.out.println(Thread.currentThread().getName() + "----");
	        }
	    }
}

class Timer {
	private static int num = 0;

//	public void add(String name) {
//
//		num++;
//		try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//		}
//		System.out.println(name + ", 你是第" + num + "个使用timer的线程");
//
//	}
	
	public void add(String name) {
		synchronized (this) {// 同步
			num++;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
			System.out.println(name + ", 你是第" + num + "个使用timer的线程");
		}
	}
	
	
}


 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值