`
chourentang
  • 浏览: 57562 次
  • 性别: 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多线程导出excel(千万级别)优化

    Java多线程导出Excel是处理大数据量时的一种高效策略,尤其在面对千万级别的数据时。传统的Apache POI库在处理大规模数据时可能会遇到栈溢出(StackOverflowError)和内存溢出(OutOfMemoryError)等问题,因为这些...

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

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

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

    Java面试的第二部分聚焦于多线程和锁机制,这些是Java并发编程的关键知识点,对于理解和优化应用程序性能至关重要。以下是对这些概念的详细说明: **并行与并发** 并行是指多个处理器或多核处理器同时处理多个任务...

    java 多线程操作数据库

    ### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...

    深入学习:Java多线程编程

    10. **性能调优**:如何根据实际需求调整线程数量,平衡CPU负载和系统响应时间,是优化多线程程序的关键。 11. **实战案例**:书中可能提供实际的并发编程例子,帮助读者将理论知识应用到实践中。 通过学习《深入...

    java多媒体与多线程处理实验

    ### Java多媒体与多线程...通过本次实验,学生不仅掌握了Java多线程编程的基础知识,还学会了如何利用多线程优化程序性能,特别是在多媒体应用领域,如动画、音视频处理等,为后续更复杂的应用开发奠定了坚实的基础。

    java多线程文件传输

    Java多线程文件传输是Java编程中一个重要的实践领域,特别是在大数据处理、网络通信和分布式系统中。在Java中,多线程可以提高程序的执行效率,尤其在处理并发任务时,如大文件的上传、下载和传输。下面将详细探讨...

    java 多线程编程实战指南(核心 + 设计模式 完整版)

    《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...

    java实现多线程文件传输

    8. **性能调优**:合理设置线程池大小、考虑使用NIO(非阻塞I/O)以减少线程等待时间、监控系统资源使用情况,都是优化多线程文件传输性能的关键。 9. **并发工具类**:`CountDownLatch`、`CyclicBarrier`和`...

    java多线程处理数据库数据

    在Java编程中,多线程处理是提升程序性能和效率的重要手段,特别是在处理大量数据库数据时。本主题将深入探讨如何使用Java的并发包(java.util.concurrent)来实现多线程对数据库数据的批量处理,包括增、删、改等...

    JAVAJAVA多线程教学演示系统论文

    《JAVA多线程教学演示系统》是一篇深入探讨JAVA多线程编程的论文,它针对教育领域中的教学需求,提供了一种生动、直观的演示方式,帮助学生更好地理解和掌握多线程技术。这篇论文的核心内容可能包括以下几个方面: ...

    java多线程进阶

    7. **线程性能优化**:如何通过合理的设计和配置来优化多线程程序的性能,例如避免过度同步、减少上下文切换、利用并发容器等。 8. **实战案例**:书中应该会包含一些实际的多线程编程案例,帮助读者将理论知识应用...

    java多线程简单下载器

    【Java多线程简单下载器】是一个初学者的编程作业,虽然代码可能较为混乱,但其核心功能已经实现,即通过多线程技术进行文件的下载。在Java中,多线程是并发处理的重要手段,它允许多个任务在同一时间执行,从而提高...

    java多线程分页查询

    #### 二、Java多线程分页查询原理及实现 ##### 1. 分页查询基础概念 分页查询是指在查询数据时,将数据分成多个页面展示,而不是一次性返回所有数据。这种方式能够有效地减少单次查询的数据量,从而提高查询速度和...

    java多线程多人聊天系统

    综上所述,Java多线程多人聊天系统涉及的技术点包括线程的创建与管理、并发控制、线程通信、异常处理、线程池、网络编程、序列化、安全性以及性能优化。通过熟练掌握这些技术,可以构建出稳定、高效且可扩展的聊天...

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

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

    JAVA多线程教材

    线程的状态包括新建、就绪、运行、阻塞和终止,理解这些状态转换对于调试和优化多线程程序至关重要。 2. **线程同步与通信**:在多线程环境中,数据共享可能导致竞态条件和死锁,Java提供了多种同步机制来避免这些...

    java多线程查询数据库

    在Java编程中,多线程查询数据库是一种常见的优化策略,特别是在处理大数据量或者需要并行执行多个查询时。本文将详细探讨如何利用Java的多线程技术和线程池来实现并发查询数据库,以及相关的文件`BatchDataUtil....

    java优化编程 java优化编程 java优化编程

    4. **并发处理**:在多线程环境中,理解和运用并发工具,如synchronized、volatile、ReentrantLock等,可以提高程序的并行性。此外,使用线程池(如ExecutorService)能有效地管理和控制线程数量,防止资源过度消耗...

Global site tag (gtag.js) - Google Analytics