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

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

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

时间: 2024-10-11 01:44:18

从头认识多线程-2.8 缓解同步方法的隐患-同步代码块的相关文章

从头认识多线程-2.9 同步代码块的特殊现象:一半同步,一半异步

这一章节我们来讨论一下同步代码块的一个特殊现象:一半同步,一半异步 1.代码清单: 1)目的:展示同步代码块的同步与异步并存的现象 2)代码功能说明: (1)建立一个测试类 (2)创建三个属性域 (3)创建三个方法,一个同步,两个不同步 (4)方法的内容是输出整数相加的结果以及相应的线程名称 (5)使用两个线程同时访问 package com.ray.deepintothread.ch02.topic_10; /** * * @author RayLee * */ public class Sy

多线程(同步代码块和同步函数)

线程安全问题 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,    另一个线程参与进来执行.导致共享数据的错误. 解决办法:    对多条操作共享数据的语句,只能让一个线程都执行完.在执行过程中,其他线程不可以参与执行. Java对于多线程的安全问题提供了专业的解决方式.就是同步代码块. synchronized(对象){    需要被同步的代码}对象如同锁.持有锁的线程可以在同步中执行.没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁.

同步代码块、同步方法以及同步锁的语法

1.同步代码块 在Thread子类run()方法代码块之外套一个下面的代码 synchronized(obj) { ... //此处就是原有的run()方法代码块 } 这里的obj就是需要锁定的对象. 2.同步方法 只要在可变类中修改方法上,加上syschronized修饰即可. 注:同步方法的同步监视器是this. 3.同步锁 先在类中定义锁对象,然后在需要保证线程安全的方法中加锁(锁变量.lock()),最后再在finally块中保证释放锁(锁变量.unlock()) class abc{

深入理解使用synchronized同步方法和同步代码块的区别

一.代码块和方法之间的区别 首先需要知道代码块和方法有什么区别: 构造器和方法块,构造器可以重载也就是说明在创建对象时可以按照不同的构造器来创建,那么构造器是属于对象,而代码块呢他是给所有的对象初始化的.底下看一个列子: public class Constructor_Methodblock { private int num; private String str; //构造器 public Constructor_Methodblock(int num,String str){ Syste

区分同步代码块、静态同步方法、非静态同步方法的锁

同步代码块.静态同步方法.非静态同步方法的锁分别是: 同步代码块可以使用自定义的Object对象,也可以使用this或者当前类的字节码文件(类名.class): 静态同步方法的锁是当前类的字节码文件(类名.class): 非静态同步方法的锁是this: 证明方法: 两个线程之间实现同步,一个线程使用同步代码块,一个线程使用同步方法. 如果这两个线程同步了,说明了使用的是同一个锁: 创建线程类(以售票为例) /** * @methodDesc 售票线程类 */ public class Threa

线程的同步机制:同步代码块&amp;同步方法

解决存在的线程安全问题:打印车票时出现重票,错票 使用同步代码块的解决方案 TestWindow2 package com.aff.thread; /* 使用实现Runnable接口的方式,售票 存在线程安全问题: 打印车票时出现重票,错票 1.原因:由于一个线程在操作共享数据过程中,未执行完毕的情况下, 另外的线程参与进来了,导致共享数据存在了安全问题 2.解决想法:让一个线程操作共享数据完毕后,其他进程才有机会参与共享数据的使用 3.java的解决方案: 线程的同步机制 方式一:同步代码块

多线程之同步代码块与同步函数

/*需求:买票分析:多个窗口卖票 是并发的,是多线程利用Runnable接口,传入一个对象,开启多线程 */class Ticket implements Runnable{ private int num=100; Object obj=new Object(); public void run(){ while(true){ synchronized(obj) { if(num>0) { System.out.println(num--+Thread.currentThread().getN

java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)

import java.util.concurrent.locks.*; class DuckMsg{ int size;//烤鸭的大小 String id;//烤鸭的厂家和标号 DuckMsg(){ } DuckMsg(int size, String id){ this.size=size; this.id=id; } public String toString(){ return id + " 大小为:" + size; } } class Duck{ private int

同步监视器之同步代码块、同步方法

如果有多个线程访问共享资源,可能会出现当一个线程没有处理完业务,然后另一个线程进入,从而导致共享资源出现不安全的情况. 日常例子:银行取钱,A和B有拥有同一个银行账户,A用存折在柜台取钱,B在取款机取钱.取钱有两个关键步骤: (1)判断账户里的钱的余额是否大于所取钱数 (2)如果大于所取钱数,则账户最终所剩余额 = 余额 - 所取钱数. 如果没有线程同步的情况下,我们假设这一种情况,这个共同的账户里共1000元. (1)A  B同时去取600元,A所在线程执行到上面的第一个步骤,判断所取钱数小于