Synchronized用法

synchronized

我们知道,synchronized可以用来修饰一个方法或者一个代码块甚至一个类,能够保证在同一时刻最多只有一个线程执行该段代码。

public synchronized void yourMethod() {
	//...
}
这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,而其他线程要想在此时调用该方法,只能排队等候。只有当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入。另一个线程仍然可以访问该object中的非synchronized同步代码块。
例子:

public class CopyOfZwThread2 extends Thread {
	
    static int tick = 0;

	public synchronized void increaseN() {
		tick++;
	}

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			try {
				increaseN();
				sleep(30);
			} catch (InterruptedException e) {
			}
		}
	}
}
对应的创建100个线程对变量进行自增:

public class RunThread {

	public static void main(String[] args) throws Exception {
		ThreadVar tv = new ThreadVar();
		Thread threads[] = new Thread[100];
		for (int i = 0; i < threads.length; i++)
			// 建立100个线程
			threads[i] = new CopyOfZwThread2();
		for (int i = 0; i < threads.length; i++)
			// 运行刚才建立的100个线程
			threads[i].start();
		for (int i = 0; i < threads.length; i++){
			threads[i].join();
			// 100个线程都执行完后继续
		}
		System.out.println(" n= " + CopyOfZwThread2.tick);
	}
}

运行完是不是发现输出并不是我们想要的 1000。Why?
其实该写法等同于下面的写法:

public void yourMethod() {
	synchronized(this) {
		//...
	}
}
即,锁是加载当前对象上的,这里是100个线程对象。与我们期待的明显不一致。可以采用下面第二种写法:
public class CopyOfZwThread2 extends Thread {
	
    static int tick2 = 0;

	// 创建一个静态钥匙
    static Object varlock = "zw";//取值任意
    
	public void increaseN2() {
		synchronized(varlock) {
			tick2++;
		}
	}

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			try {
				increase();
				sleep(30);
			} catch (InterruptedException e) {
			}
		}
	}
}
此时,锁是基于”钥匙“对象的,只有拿到钥匙才能对变量自增。

这里需要注意的是,synchronized后面括号里的一定要是引用类型。比如可以是Integer 类型,但不能是int。很简单,基本类型都是传值使用当然无法满足需要了。有兴趣的可以试下 int,发现会有编译错:int is not a valid type's argument for the synchronized statement。

当然,synchronized还能加在静态代码块上,下面代码一个加了synchronized,另一个没加:

	synchronized public static void printA() {
    	System.out.println("线程" + Thread.currentThread().getName() + " come to printA");
    	try {
        	tick++;
        	sleep(30);
        } catch (InterruptedException e) {
		}
    	System.out.println("线程" + Thread.currentThread().getName() + " leave to printA");
    }
    
    public static void printB() {
    	System.out.println("线程" + Thread.currentThread().getName() + " come to printB");
        try {
        	tick2++;
        	sleep(30);
        } catch (InterruptedException e) {
		}
        System.out.println("线程" + Thread.currentThread().getName() + " leave to printB");
    }

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			try {
				printA();
				printB();
				sleep(30);
			} catch (InterruptedException e) {
			}
		}
	}
最后输出部分如下:

线程53  come to printA
线程53  leave to printA
线程52  leave to printB
线程53  come to printB
线程54  come to printA
线程54  leave to printA
线程56  come to printA
线程54  come to printB    (53尚未离开printB)
线程53  leave to printB
线程54  leave to printB
线程56  leave to printA
线程56  come to printB
线程57  come to printA
线程57  leave to printA
线程56  leave to printB
线程55  come to printA
线程57  come to printB
线程57  leave to printB
....
 tick= 1000    (最后是 1000 意味着同步的)
 tick2= 1000
从上面的输出可以看出,对静态代码块加 synchronized 实现了同步。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值