继续上一文。
运行结果如下:
Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-0: 4
Thread-0: 5
Thread-1: 6
Thread-1: 7
Thread-0: 8
Thread-0: 9
Thread-0: 10
Thread-1: 11
Thread-1: 2
Thread-1: 3
Thread-0: 4
Thread-0: 5
Thread-1: 6
Thread-1: 7
Thread-0: 8
Thread-0: 9
Thread-0: 10
Thread-1: 11
运行结果似乎不完善,因为多打了一个11出来!哈哈
这个现象只能说明,锁块加的不理想!
这个是,刚才加锁后的线程类ShareDataThread.java:
package thread;
public class ShareDataThread implements Runnable {
private int i = 0;
@Override
public void run() {
while (i < 10) {
synchronized(this){
i++;
for (int j = 0; j < 10000000l; j++)
;
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
我再细细的分析一下

- 其实造成程序多打印出来一个11,得根本原因是
- (i〈10)这个语句没有加锁的原因,导致的。
- 但是while循环内部已经都加好锁了,
- while循环外部,如果加锁,那么无法实现多线程共用数据的效果(不信?你们可以自己试一下)
- 好吧,怎么破?!!!!
小妹绞尽脑汁,修改代码后如下(以下两种方式都可以):
1锁块方式:
package thread;
public class ShareDataThread implements Runnable {
private int i = 0;
@Override
public void run() {
while (true) {
synchronized(this){
if(i >= 10) break;
i++;
for (int j = 0; j < 10000000l; j++)
;
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
2锁方法方式(劈分成小的方法体后,再加锁):
package thread;
public class ShareDataThread implements Runnable {
private int i = 0;
@Override
public void run() {
while (true) {
boolean isFinished = subMethod();
if(isFinished)break;
}
}
public synchronized boolean subMethod() {
boolean isFinished = false;
if (i >= 10){
return true;
}
i++;
for (int j = 0; j < 10000000l; j++);
System.out.println(Thread.currentThread().getName() + ": " + i);
return isFinished;
}
}
执行类不变:
package thread;
public class OneObjExample {
public static void main(String abc[]) {
ShareDataThread s1 = new ShareDataThread();
Thread t1 = new Thread(s1);
Thread t2 = new Thread(s1);
t1.start();
t2.start();
}
}
运行结果(以让两种修改方式,都运行结果完美

Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-0: 4
Thread-0: 5
Thread-0: 6
Thread-0: 7
Thread-0: 8
Thread-1: 9
Thread-1: 10
(注意,每次运行结果都是,从1打印到10,但是Thread1和Thread0到底哪个线程打印了多少次,都是随机的,是cpu调度的,人为不可控的哦。)
综上所述
给代码加锁,是一门学问,需要细细揣摩,多测试,多分析结果,才能给锁加对地方。
线程状态图更新如下:
根据更新后的线程状态图,来说明一下,多线程中,锁的执行情况:
- 首先一个线程类的对象,不管该线程类里面写了多少个synchronized的程序块,一个对象只有一个锁。
- 比如代码里面:ShareDataThread s1 = new ShareDataThread(); // s1是一个线程对象,run方法里面写了一个synchronized的程序块,那么它只有一个锁
- 不管s1开启了多少个线程,那么它只有一个锁!!!!!!!!
- 同一时刻只有一个线程取得了锁(lock)
- 以上面的代码为例,thread0和thread1同时运行
- 当thread0运行到锁块的时候,会首先进入到“lock pool”里面,然后尝试拿s1对象的锁
- 如果锁没有被别人拿到,那么thread0就可以拿到了,thread0进入到“Runnable”状态,等待cpu调度,去执行锁块里面的内容
- 当thread1运行到锁块的时候,也会首先进入到“lock pool”里面,然后尝试拿s1对象的锁
- 如果锁被别人拿到了,那么thread1,就拿不到锁,thread1一直在“lock pool”里面,等待拿锁。
- thread0当锁块里面的内容都执行完毕之后,就会归还锁。
- thread0当又一次运行到锁块的时候,又先进入到“lock pool”里面
- 注意此时,“lock pool”里面有连个线程啦:thread0和thread1,同时等待拿锁。
- 那么,thread0和thread1这两个线程就靠运气了,看看谁能抢到锁(都是随机的哦,认为不可控的)
- 拿到锁的线程,进入runnable状态。
- 好吧,循环往复,直到线程进入死亡状态为止。