Vince_Zh的博客

记录平时所学所想,不足之处,欢迎指正。

Java中synchronized使用的一点见解

第一篇文章,我先简单介绍下我的情况。普通一本院校的软件工程专业本科学生。现阶段大四,在北京中软国际进行实训。

培训的方向是java 企业级开发。在中软已经培训了一个月多。培训是从零开始学起。所以又从最基本的语法开始学习。第二次学习总是感受颇深。有些地方也有了新的感悟。很多以前不接触的语法或知识也逐渐掌握。

第一次接触java中的synchronize关键字应该是在操作系统课程的实验课上。要求做哲学家进餐问题。使用锁机制,某一线程代码段的原子性。当时使用了一个单独的类,在类中定义了一个静态Object变量当作锁。而所有线程中synchronize代码块均对该object变量加锁,以实现其 查看标识变量并更改标识变量 的原子操作。此处不再详述。

最近重学线程一块。无论是老师讲课,还是网上,总是要求区分synchronize锁方法,锁this,锁对象甚至锁class的区别。而在我的理解,锁方法等同与锁this。

锁方法:

public synchronized void method()
{
  //do some thing
}

public void method() {
		synchronized (this) {
			// do some thing
		}
	}


具有相同的使用效果。即当两个线程同时访问同一个对象的同步代码(锁this)块或同步方法(锁方法),只有一个线程可以得到执行。另一个线程受到阻塞。当两线程访问同一个类的不同对象时,不会产生阻塞。

再说一下锁对象,即锁某个object。

public class MyThread implements Runnable {
	public static void main(String[] args) {
		MyThread m1 = new MyThread();
		MyThread m2 = new MyThread();
		Thread t1 = new Thread(m1);
		Thread t2 = new Thread(m2);
		t1.start(); t2.start();
	}

	public void run() {
		synchronized (Locker.num) {
			for (int i = 0; i < 5; i++)
				System.out.println(Thread.currentThread().getName());
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
public class Locker {
	public static Integer num = 0;
}


相信学习过java的人也一定能理解。这个代码产生的结果将是其中一个线程将同步块执行完后。另一个线程才可能进入同步块执行。即另一个线程被阻塞。

运行结果如下

Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-1
Thread-1
Thread-1
Thread-1
Thread-1


然后这时候,老师或者网上就总会对你说,他们都对同一个对象上了锁。把这个对象锁住了。所以别的线程不能再对其进行加锁,修改等操作。

但我理解的是,对象是一个锁。而被加锁的是{}中的代码。若是同一个对象,那就是同一把锁。既然这把锁已经被别的线程用了且锁住了。所以这个线程就无法获得这个锁,进而进入了等待状态,直到占用了锁的线程将锁释放。

在使用这个对象锁的时候。并不影响其他线程对这个对象进行读或修改的操作。这也就是所谓的加锁的是{}代码块,而非()中的对象。

public class Runnable1 implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			//R1对Locker.num对象进行修改但不上锁
			System.out.println("R1:" + ++Locker.num);
			try {
				Thread.sleep(20);
			} catch (Exception e) {
			}
		}
	}
}
public class Runnable2 implements Runnable {
	@Override
	public void run() {
		// R2对Locker.num对象进行上锁
		synchronized (Locker.num) {
			for (int i = 0; i < 10; i++) {
				System.out.println("R2:" + --Locker.num);
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
public class test {
	public static void main(String[] args) {
		Family family = new Family();
		family.money = 100.0;
		Runnable1 r1 = new Runnable1();
		Runnable2 r2 = new Runnable2();
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);
		t1.start();
		t2.start();
	}
}
R2:-1
R1:1
R2:0
R1:2
R1:1
R2:-1
R2:0
R1:1
R2:0
R1:2
R2:-1
R1:1
R1:2
R2:0
R1:1
R2:-1
R1:0
R2:-1
R1:0
R2:-2

结果如上图。即R2对Lock.num的加锁并没有影响到R1对Lock.num的读写。

所以无论是锁this,锁object,锁Object.class(其本质也是一个静态对象) 要想知道其是否会造成阻塞,只可单线程进入代码块,而非交叉运行,只需分辨不同线程中同步代码块()中的对象是否为同一个即可。若为同一个。则可以实现阻塞,否则互不影响。

一句话总结,不同线程中,具有相同对象锁的代码块中语句不可交叉执行,会发生阻塞。





阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Vince_Zh/article/details/52355567
文章标签: java 线程 同步
个人分类: Java
下一篇Spring 事务的简单使用
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭