第一篇文章,我先简单介绍下我的情况。普通一本院校的软件工程专业本科学生。现阶段大四,在北京中软国际进行实训。
培训的方向是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(其本质也是一个静态对象) 要想知道其是否会造成阻塞,只可单线程进入代码块,而非交叉运行,只需分辨不同线程中同步代码块()中的对象是否为同一个即可。若为同一个。则可以实现阻塞,否则互不影响。
一句话总结,不同线程中,具有相同对象锁的代码块中语句不可交叉执行,会发生阻塞。