从头认识多线程-2.9 缓解同步方法的隐患-同步代码块

这一章节我们来讨论一下缓解同步方法的隐患-同步代码块。

1.思路:把同步方法,降低同步的粒度,同步到代码块


2.根据上一章节的例子,我们把代码修改一下

(1)第一种方法,把同步标记移到更新的那一栏里面去,一般来说大部分都是更新的时候需要同步数据

package com.ray.deepintothread.ch02.topic_9;

/**
 * 从头认识多线程-2.8 缓解同步方法的隐患-同步代码块<br>
 * 
 * @author RayLee
 *
 */
public class ReliefThreatOfSynch {
	public static void main(String[] args) throws InterruptedException {
		MyService myService = new MyService();
		ThreadOne threadOne = new ThreadOne(myService);
		Thread thread = new Thread(threadOne);
		thread.start();
		ThreadTwo threadTwo = new ThreadTwo(myService);
		Thread thread2 = new Thread(threadTwo);
		thread2.start();

		Thread.sleep(10000);
		System.out.println("application use time:" + (MyTimeUtil.END_TIME - MyTimeUtil.START_TIME));
	}
}

class ThreadOne implements Runnable {

	private MyService myService;

	public ThreadOne(MyService myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		myService.service();
	}
}

class ThreadTwo implements Runnable {

	private MyService myService;

	public ThreadTwo(MyService myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		myService.service();
	}
}

class MyService {

	private void queryDataFromServer() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 增加同步机制
	 */
	private synchronized void updateDataFromServer() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private void retrunDataFromServer() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void service() {
		long startTime = System.currentTimeMillis();
		if (MyTimeUtil.START_TIME == 0) {
			MyTimeUtil.START_TIME = startTime;
		}
		queryDataFromServer();
		updateDataFromServer();
		retrunDataFromServer();
		long endTime = System.currentTimeMillis();
		if (endTime > MyTimeUtil.END_TIME) {
			MyTimeUtil.END_TIME = endTime;
		}
		System.out.println("Thread name:" + Thread.currentThread().getName() + " user time:" + (endTime - startTime));
	}
}

class MyTimeUtil {
	public static long START_TIME = 0;
	public static long END_TIME = 0;
}

输出:

Thread name:Thread-0 user time:3000
Thread name:Thread-1 user time:4000
application use time:4000


(2)第二种方法,直接调用方法的时候加上同步标志

package com.ray.deepintothread.ch02.topic_9;

/**
 * 从头认识多线程-2.8 缓解同步方法的隐患-同步代码块<br>
 * 
 * @author RayLee
 *
 */
public class ReliefThreatOfSynch2 {
	public static void main(String[] args) throws InterruptedException {
		MyService2 myService = new MyService2();
		ThreadThree threadThree = new ThreadThree(myService);
		Thread thread = new Thread(threadThree);
		thread.start();
		ThreadFour threadFour = new ThreadFour(myService);
		Thread thread2 = new Thread(threadFour);
		thread2.start();

		Thread.sleep(10000);
		System.out.println("application use time:" + (MyTimeUtil2.END_TIME - MyTimeUtil2.START_TIME));
	}
}

class ThreadThree implements Runnable {

	private MyService2 myService;

	public ThreadThree(MyService2 myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		myService.service();
	}
}

class ThreadFour implements Runnable {

	private MyService2 myService;

	public ThreadFour(MyService2 myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		myService.service();
	}
}

class MyService2 {

	private void queryDataFromServer() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private void updateDataFromServer() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private void retrunDataFromServer() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void service() {
		long startTime = System.currentTimeMillis();
		if (MyTimeUtil2.START_TIME == 0) {
			MyTimeUtil2.START_TIME = startTime;
		}
		queryDataFromServer();
		synchronized (this) {
			updateDataFromServer();
		}
		retrunDataFromServer();
		long endTime = System.currentTimeMillis();
		if (endTime > MyTimeUtil2.END_TIME) {
			MyTimeUtil2.END_TIME = endTime;
		}
		System.out.println("Thread name:" + Thread.currentThread().getName() + " user time:" + (endTime - startTime));
	}
}

class MyTimeUtil2 {
	public static long START_TIME = 0;
	public static long END_TIME = 0;
}

输出:

Thread name:Thread-0 user time:3002
Thread name:Thread-1 user time:4002
application use time:4002


结果跟上面的差不多,基本认为是一样的


3.思考

虽然上面的方法能够缓解同步方法时所出现的问题,但是还没有根本解决,也暂时不可能解决,因此,除了上面的方法,我们还有:

(1)降低业务复杂度,从业务的角度去优化(先跳出技术的角度)

(2)增强硬件设置(跳出软件的角度)

(3)增加网络(跳出软件的角度)

(4)优化代码


总结:这一章节我们讨论了使用同步代码块缓解同步方法的隐患。


这一章节就到这里,谢谢

------------------------------------------------------------------------------------

我的github:https://github.com/raylee2015/DeepIntoThread


目录:http://blog.csdn.net/raylee2007/article/details/51204573


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值