java线程研究---(8)Thread同步:锁的概念

时间:2021-07-15 23:29:46

(多线程数据共用的)示例代码:
先来看看“java线程研究---(7)Thread同步:多线程数据共用会产生问题”这篇文章里面主要的代码例子


ShareDataThread.java

package thread;

public class ShareDataThread implements Runnable {

private int i = 0;

@Override
public void run() {
while (i < 10) {
i++;
for (int j = 0; j < 10000000l; j++)
;
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}


OneObjExample.java
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: 3
Thread-0: 4
Thread-1: 5
Thread-0: 6
Thread-1: 7
Thread-1: 8
Thread-0: 9
Thread-1: 10
Thread-0: 10


分析运行结果:

我就如上的结果,有如下的分析(或者说猜测,因为多线程这东西,只能根据现象去揣测,无从得知底这两个线程是如何交替运行的java线程研究---(8)Thread同步:锁的概念):

  1. 为什么2没有打印出来?
    • thread-1打印1完毕之后,
    • thread-1继续执行i++
    • thread-1接着执行for循环,由于执行for循环需要较长的时间,
    • thread-1还没有来得及打印2,thread-1就被cpu替换下来了。。。
    • thread-0开始执行,此时thread-0所拿到的i=2, 
    • thread-0,在执行i++之后,i=3
    • thread-0接着执行for循环,由于执行for循环需要较长的时间,
    • thread-0还没有来得及打印3,thread-0就被cpu替换下来了。。。
    • thread-1开始执行,此时thread-1所拿到的i=3,
    • 注意,此时thread-1是继续上一次他被cpu替换下来的点继续执行,所以
    • thread-1直接开始打印3!
    • 大家多读读几遍,看看我分析的对不?

  2. 为什么打印两个10?
    • 其实也很好分析
    • Thread-1,在要打印之前,被cpu替换下来
    • Thread-1再被cpu调用,开始执行的时候,所拿到的i=10。由于是继续上一次代码行号执行,所以
    • Thread-1执行打印10。
    • Thread-1继续while循环,但是条件不成立,while循环结束,Thread-1进入死亡状态。
    • Thread-0,也是在要打印之前,被cpu替换下来
    • Thread-0再被cpu调用,开始执行的时候,所拿到的i依旧是10。由于是继续上一次代码行号执行,所以
    • Thread-0执行打印10。
    • Thread-0继续while循环,但是条件不成立,while循环结束,Thread-0也进入死亡状态。
    • 小妹分析的太深入了,有木有java线程研究---(8)Thread同步:锁的概念

结论总结: 针对于这个示例代码,和打印的结果,综合分析,我的总结就是:
  • i++
  • for循环
  • 打印
  • 这三行代码,只要被其他线程进来,分割,侵入,就会造成数据打印不一致的结果。
  • 因此,得让这三行代码,具有原子性!不可分割,无法被其他线程进来侵入,打断这三行代码连续执行
  • 所以给这三行代码加锁,那么这三行代码就变成了一个整体,具有原子性!
  • 好啦,锁的概念,由此诞生!

锁:synchronized
之前的文字,都是为了现在,引入锁的概念,为什么有锁,加锁的目的等——锁就是为了解决多线程的数据同步问题的
话不多说,直接看上锁之后的代码java线程研究---(8)Thread同步:锁的概念
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);
}
}
}
}

OneObjExample.java 执行类,不变

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-1: 6
Thread-1: 7
Thread-0: 8
Thread-0: 9
Thread-0: 10
Thread-1: 11



注意:运行结果,似乎不怎么尽如人意,稍后我会继续完善的。