多线程下synchronized修饰static方法与非static方法的区别

一直对多线程的概念比较模糊,今天就写了个关于变量原子操作的小程序,好让自己加深一下理解

代码如下:

package atomic;

public class JoinThread extends Thread {

	public static int i = 0;

	//public static AtomicInteger atomicInteger = new AtomicInteger(0);
	
	public synchronized void inc(){
		i ++;
	}
	@Override
	public void run() {
		for (int x = 0; x < 10; x++) {
			inc();
			try {
				Thread.sleep(33);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		// JoinThread jt = new JoinThread();
		Thread[] t = new Thread[100];
		for (int i = 0; i < t.length; i++) {
			t[i] = new JoinThread();
		}
		for (int i = 0; i < t.length; i++) {
			t[i].start();
		}
		for (int i = 0; i < t.length; i++) {
			t[i].join();
		}
		System.out.println(JoinThread.i);
	}

}

执行完发现,i并没有如想像中的输出1000,即使i添加volatile进行修饰,也不会输出1000,值是随机变化的。


将inc()方法添加static修饰,结果无问题,准确无误的输出1000。


另外一种改法,将代码改成:

Thread[] t = new Thread[100];
for (int i = 0; i < t.length; i++) {
	t[i] = new JoinThread();
}
修改成:

JoinThread jt = new JoinThread();
Thread[] t = new Thread[100];
for (int i = 0; i < t.length; i++) {
	t[i] = new Thread(jt);
}
结果无问题,准确无误的输出1000


这里主要涉及到类对象(static方法),对象方法(非static方法)

我们知道,当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例);

当synchronized修饰一个非static方法时,多线程下,获取的是对象锁(即类的实例对象)

所以,当synchronized修饰一个static方法时,创建线程不管是new JoinThread()还是new Thread(new JoinThread()),在run方法中执行inc()方法都是同步的;

相反,当synchronized修饰一个非static方法时,如果用new JoinThread()还是new Thread(new JoinThread())方式创建线程,就无法保证同步操作,因为这时

inc()是属于对象方法,每个线程都执有一个独立的对象实例new JoinThread(),所以多线程下执行inc()方法并不会产生互斥,也不会有同步操作。


另外如果考虑到变更的原子操作,可使用atomic包下面的包装对象,这些对象都是对volatile修饰变量的一种延伸,可保证变量的原子操作而不用去同步方法或

代码块是否同步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章