`
chourentang
  • 浏览: 56547 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

java优化之二:多线程优化

    博客分类:
  • Java
阅读更多
1.Future模式
    假如有一个执行起来需要花费一些时间的方法,为了省去不必要的等待执行结果出来,继续做别的事情,则可以事先获取一个“提货单”即Future参与者,Future Pattern模式也就是这样的方式,当一个线程需要另一个线程的处理的结果时候,则不必一直等着处理结果,可以先处理别的事情,提前拿个Future对象,再过一段时间来获取另一个线程的处理结果。
   在多个线程中,返回另一个线程的执行结果,最简单的就是采用主线程调用子线程后,一直无限循环等待子线程处理结果。由于这种会浪费等待的时间,且会浪费CPU,在此基础上,进而在子线程中调用主线程的方法来实现。可以利用静态方法和实例方法,在利用实例方法中就需要在调用子线程的时候通过构造器将主线程对象的实例传递给子线程使用。但是这种方式还欠缺一些灵活性,主线程的方法是由子线程调用的,至于什么时候该方法被调用则不清楚,不利于主线程处理。
    为了改变这种模式,则就利用Future Pattern,主线程调用子线程后,继续执行程序,只是在调用子线程后,暂时获取一个临时对象Future,这样在主线程想获取Future内部数据的时候,就可以调用Future的方法,如果该方法中已经有了处理结果,则此时就可以立刻获取,如果没有则主线程就需要稍微等一下返回结果。这种方式的优点就是主线程可以任何时候调用返回的结果,主线程不必长等待返回的结果。

模拟一个future的例子:
public interface Data {
	public String getData();
}


public class RealData implements Data {
	protected final String result;
	
	public RealData(String param) {
		StringBuffer sb = new StringBuffer();
		for(int i = 0; i < 10; i++) {
			sb.append(param);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		result = sb.toString();
	}

	@Override
	public String getData() {
		return result;
	}

}


public class FutureData implements Data {
	protected RealData realData = null;
	protected boolean isReady = false;
	
	public synchronized void setRealData(RealData realData) {
		if(isReady) {
			return;
		}
		this.realData = realData;
		isReady = true;
		notifyAll();
	}

	@Override
	public synchronized String getData() {
		while(!isReady) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return realData.result;
	}

}


public class Client {
	public Data request(final String queryStr) {
		final FutureData future = new FutureData();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				RealData realData = new RealData(queryStr);
				future.setRealData(realData);
			}
		}).start();
		
		return future;
	}
}


public class FutureTest {
	public static void main(String[] args) {
		Client client = new Client();
		Data data = client.request("name");
		System.out.println("请求已发送...");
		
		System.out.println("做其他事...");
		for(int i = 0; i < 3; i++) {
			System.out.println(i);
		}
		
		System.out.println("获取的数据:" + data.getData());
	}
}
请求已发送...
做其他事...
0
1
2
获取的数据:namenamenamenamenamenamenamenamenamename


JDK提供的Future模式使用:
由于future模式比较常用,jdk内置了future模式的实现,其除了future模式的基本功能外,还可以取消或停止future 任务。
public class RealData implements Callable<String> {
	private String param;
	
	public RealData(String param) {
		this.param = param;
	}

	@Override
	public String call() throws Exception {
		StringBuffer sb = new StringBuffer("param:" + param + " content:");
	
		System.out.println("---- 费时的业务逻辑  ----");
		for(int i = 0; i < 10; i++) {
			sb.append(i);
			Thread.sleep(500);
		}
		
		return sb.toString();
	}
	
}


public class FutureTest {
	public static void main(String[] args) {
		System.out.println("---- 发送请求  ----");
		FutureTask<String> future = new FutureTask<String>(new RealData("www.dodo.com/xx"));
		ExecutorService executor = Executors.newFixedThreadPool(1);
		executor.submit(future);
		
		System.out.println("---- 做其他事情1  ----");
		for(int i = 0; i < 3; i++) {
			System.out.println(i);
		}
		
		System.out.println("---- 获取结果  ----");
		try {
			System.out.println(future.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		
		System.out.println("---- 做其他事情2  ----");
		for(int i = 0; i < 3; i++) {
			System.out.println(i);
		}
		
		executor.shutdownNow();
	}
}
---- 发送请求  ----
---- 做其他事情1  ----
0
1
2
---- 获取结果  ----
---- 费时的业务逻辑  ----
param:www.dodo.com/xx content:0123456789
---- 做其他事情2  ----
0
1
2


2.接口的回调
回调的概念:
通常情况下,我们创建一个对象,并马上直接调用它的方法。然而,在有些情况下,希望能在某个场景出现后或条件满足时才调用此对象的方法。回调就可以解决这个“延迟调用对象方法”的问题。这个被调用方法的对象称为回调对象。

实现回调的原理简介如下:
首先创建一个回调对象,然后再创建一个控制器对象,将回调对象需要被调用的方法告诉控制器对象。控制器对象负责检查某个场景是否出现或某个条件是否满足。当此场景出现或此条件满足时,自动调用回调对象的方法。

模拟Android中常用的图片下载:
相对于android中最一般的方式新开线程下载图片(handler+thread或AsyncTask),这种方式处理更优雅、更简单、体验更好。通过给下载图片定义一个回调接口,当图片下载完成,会执行主线程中接口中的内容。
public class ImageDownload {
    
    public void downloadImage(final String url, final DownloadListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("---- 费时的图片下载操作  ----");
                StringBuilder sb = new StringBuilder("image bytes: ");
                if(url != null) {
                    try {
                        for(int i = 0; i < 10; i++) {
                            Thread.sleep(500);
                            sb.append(i);
                        }
                        listener.getResult(sb.toString());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
    
    public interface DownloadListener {
        public void getResult(String result); 
    }
}


public class CallBackTest {
    private static String imageContent;
    
    public static void main(String[] args) {
        ImageDownload downloader = new ImageDownload();
        System.out.println("---- 开始下载图片  ----");
        downloader.downloadImage("www.baidu.com/abc", new ImageDownload.DownloadListener() {
            @Override
            public void getResult(String result) {
                imageContent = result;
                System.out.println("---- 图片下载完成  ----");
                System.out.println("imageContent: " + imageContent);
            }
        });
        
        System.out.println("---- 做其他事情  ----");
        for(int i = 0; i < 3; i++) {
            System.out.println(i);
        }
        
        System.out.println("---- 图片未下载完成  ----");
        System.out.println("imageContent: " + imageContent);
    }
}

输出结果:
---- 开始下载图片  ----
---- 做其他事情  ----
0
1
2
---- 图片未下载完成  ----
imageContent: null
---- 费时的图片下载操作  ----
---- 图片下载完成  ----
imageContent: image bytes: 0123456789


3.Master-Worker模式
Master-Worker模式用于将串行任务并行化,一个任务被分解为几个任务分别处理,然后将各个子任务汇总处理,如多线程下载即时利用这种方式实现的。

利用Master-Worker模式做1-100的立方和:
public class Worker implements Runnable {
	protected Queue<Object> workQueue;
	protected Map<String, Object> resultMap;
	
	public void setWorkQueue(Queue<Object> workQueue) {
		this.workQueue = workQueue;
	}
	
	public void setResultMap(Map<String, Object> resultMap) {
		this.resultMap = resultMap;
	}
	
	public Object handle(Object input) {
		return input;
	}
	
	@Override
	public void run() {
		while(true) {
			Object input = workQueue.poll();
			if(input == null) {
				break;
			}
			Object result = handle(input);
			resultMap.put(Integer.toString(input.hashCode()), result);
		}
	}

}


public class Master {
	protected Queue<Object> workQueue = new ConcurrentLinkedQueue<Object>();
	protected Map<String, Thread> threadMap = new HashMap<String, Thread>();
	protected Map<String, Object> resultMap = new ConcurrentHashMap<String, Object>();
	
	public boolean isComplete() {
		for(Map.Entry<String, Thread> entry : threadMap.entrySet()) {
			if(entry.getValue().getState() != Thread.State.TERMINATED) {
				return false;
			}
		}
		return true;
	}
	
	public Master(Worker worker, int workeNumber) {
		worker.setWorkQueue(workQueue);
		worker.setResultMap(resultMap);
		
		for(int i = 0; i < workeNumber; i++) {
			threadMap.put(Integer.toString(i), new Thread(worker, Integer.toString(i)));
		}
	}
	
	public void submit(Object obj) {
		workQueue.add(obj);
	}
	
	public Map<String, Object> getResultMap() {
		return resultMap;
	}
	
	public void execute() {
		for(Map.Entry<String, Thread> entry : threadMap.entrySet()) {
			entry.getValue().start();
		}
	}
}


public class CubeWorker extends Worker {
	
	@Override
	public Object handle(Object input) {
		Integer i = (Integer)input;
		return i*i*i;
	}
	
}


public class MasterWorkerTest {
	
	public static void main(String[] args) {
		Master master = new Master(new CubeWorker(), 5);
		
		for(int i = 0; i < 100; i++) {
			master.submit(i);
		}
		
		master.execute();
		
		int result = 0;
		Map<String, Object> resultMap = master.getResultMap();
		while(resultMap.size() > 0 || !master.isComplete()) {
			Set<String> keys = resultMap.keySet();
			String key = null;
			for(String k : keys) {
				key = k;
				break;
			}
			Integer i = null;
			if(key != null) {
				i = (Integer) resultMap.get(key);
			}
			if(i != null) {
				result += i;
			}
			if(key != null) {
				resultMap.remove(key);
			}
		}
		
		System.out.println(result);
	}
}
24502500


4.不变模式
  不变模式是指一个对象被创建,则它的内部状态永远不会发生改变,这样就在多线程操作中就不需要同步,提高了性能。
  不变模式的使用场景:
  1- 对象被创建后内部状态不在发生改变
  2- 对象需要被共享,被多线程访问
  不变模式的构建方式:
  1- 去除Setter及所有能够修改自身属性的方法
  2- 所有属性标记为private,并且用final标记
  3- 确保没有子类可以修改和重载它的行为
  4- 有一个可以创建完整对象的构造函数

  如String类就是典型的不变模式


5.生产者-消费者模式
  暂无,后补
分享到:
评论

相关推荐

    Java第19讲:多线程(1).txt

    什么是线程 ... 举例:电脑管家同时进行清理垃圾、查杀修复、优化加速,这就是多线程。 如果是单线程的话,在运行清理垃圾时,其它两个都得在等待,不能运行。 多线程提高效率,同时运行。

    java多线程导出excel(千万级别)优化

    轻松解决普通poi形式导出Excel的中出现的栈溢出问题,此资源可实现千万级数据分批导出csv文件,csv大数据量导出(千万级别,不会内存溢出),多线程导出 ,生产环境已经很稳定的使用着

    java面试第二部分:多线程与锁

    锁升级、虚拟机锁优化、锁的实现原理、线程安全、可重入锁、线程池的实现等常见的面试问题

    多线程导出Excel(百万级别)_Java版优化.zip

    用开源 Apache POI 技术导出Excel,解决导出大数据出现OOM、栈溢出问题,此资源可实现百万级数据多线程分批导出Excel文件,不会内存溢出,生产环境已很稳定的使用者,所以用到的技术很核心、值得参考

    Java程序性能优化

    《Java程序性能优化:让你的Java程序更快、更稳定》以Java性能调优为主线,系统地阐述了与Java性能优化相关的知识与技巧。《Java程序性能优化:让你的Java程序更快、更稳定》共6章,先后从软件设计、软件编码、JVM调优...

    Java多线程优化百万级数据

    通过实例给出利用Java多线程优化读取数据库百万级别数据

    java程序性能优化

    《Java程序性能优化:让你的Java程序更快、更稳定》以Java性能调优为主线,系统地阐述了与Java性能优化相关的知识与技巧。  《Java程序性能优化:让你的Java程序更快、更稳定》共6章,先后从软件设计、软件编码、...

    基于Java多线程技术实现的粒子群优化算法

    Java实现的 基于Java多线程技术实现的粒子群优化算法pdf

    Java性能调优实战——覆盖80%以上的Java应用调优场景

    避免使用Java序列化14讲多线程之锁优化(下):使用乐观锁优化并行操作16讲多线程调优(下):如何优化多线程上下文切换17讲并发容器的使用:识别不同场景下最优容器21讲深入JVM即时编译器JIT,优化Java编译25讲答疑...

    Java优化编程(第2版)

    Java优化编程(第2版)通过丰富、完整、富有代表性的实例,展示了如何提升Java应用性能,并且给出了优化前与优化后的Java应用程序的性能差别,以实际的实例与数字告诉你,为什么不可以这么做,应该怎么做,深入分析...

    阿里巴巴Java性能调优实战(2021-2022华山版)+Java架构核心宝典+性能优化手册100技巧.rar

    模块三,多线程性能调优。 模块四,JVM 性能监测及调优。 模块五,设计模式调优。 模块六,数据库性能调优。 模块七,实战演练场。 性能优化手册是一套java性能学习研究小技巧,包含内容:Java性能优化、JVM性能优化...

    Java性能优化实战视频全集

    13 案例分析:多线程锁的优化.mp4 14 案例分析:乐观锁和无锁.mp4 15 案例分析:从BIO到NIO,再到AI0.mp4 16 案例分析:常见Java代码优化法则.mp4 17 高级进阶:JVM如何完成垃圾回收?.mp4 18 高级进阶:JIT如何...

    奇偶数交互多线程thread源码java

    16:55:20.675 [main] INFO org.malin.allutils.makefile.ReadFileNameUtil - 获取到 文件名称: 10.并发调试和JDK8新特性.pdf 16:55:20.677 [main] INFO org.malin.allutils.makefile....锁的优化和注意事项.pdf

    多线程下的单例模式优化

    这是一个关于多线程下的单例模式优化代码。public class Singleton { private static Singleton instance; private Singleton (){ } public static Singleton getInstance(){ //对获取实例的方法进行同步 if...

    JAVA线程安全及性能的优化

    其实JAVA的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...

    java多线程文件传输(基于swing)

    基于socket的多线程文件传输,包中含有整个工程的源代码(有详细的注解) 和 直接运行的打包生成的jar文件 。其中swing界面有待优化.....

    基于Java多线程技术实现的粒子群优化算法.kdh

    基于Java多线程技术实现的粒子群优化算法.kdh

Global site tag (gtag.js) - Google Analytics