java线程研究---(9)Thread同步:如何加锁

继续上一文。

运行结果如下:

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

运行结果似乎不完善,因为多打了一个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);
			}
		}
	}
}

我再细细的分析一下
《java线程研究---(9)Thread同步:如何加锁》

  • 其实造成程序多打印出来一个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();
	}
}

运行结果(以让两种修改方式,都运行结果完美
《java线程研究---(9)Thread同步:如何加锁》):

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调度的,人为不可控的哦《java线程研究---(9)Thread同步:如何加锁》。)


综上所述

给代码加锁,是一门学问,需要细细揣摩,多测试,多分析结果,才能给锁加对地方。

线程状态图更新如下:

《java线程研究---(9)Thread同步:如何加锁》

根据更新后的线程状态图,来说明一下,多线程中,锁的执行情况:

  • 首先一个线程类的对象,不管该线程类里面写了多少个synchronized的程序块,一个对象只有一个锁。
  • 比如代码里面:ShareDataThread s1 = new ShareDataThread(); // s1是一个线程对象,run方法里面写了一个synchronized的程序块,那么它只有一个锁
  • 不管s1开启了多少个线程,那么它只有一个锁!!!!!!!!
  • 同一时刻只有一个线程取得了锁(lock)
  1. 以上面的代码为例,thread0和thread1同时运行
  2. 当thread0运行到锁块的时候,会首先进入到“lock pool”里面,然后尝试拿s1对象的锁
  3. 如果锁没有被别人拿到,那么thread0就可以拿到了,thread0进入到“Runnable”状态,等待cpu调度,去执行锁块里面的内容
  4. 当thread1运行到锁块的时候,也会首先进入到“lock pool”里面,然后尝试拿s1对象的锁
  5. 如果锁被别人拿到了,那么thread1,就拿不到锁,thread1一直在“lock pool”里面,等待拿锁。
  6. thread0当锁块里面的内容都执行完毕之后,就会归还锁。
  7. thread0当又一次运行到锁块的时候,又先进入到“lock pool”里面
  8. 注意此时,“lock pool”里面有连个线程啦:thread0和thread1,同时等待拿锁。
  9. 那么,thread0和thread1这两个线程就靠运气了,看看谁能抢到锁(都是随机的哦,认为不可控的)
  10. 拿到锁的线程,进入runnable状态。
  11. 好吧,循环往复,直到线程进入死亡状态为止。

    原文作者:java锁
    原文地址: https://blog.csdn.net/miqi770/article/details/48177027
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞