java优化之二:多线程优化

[b]1.Future模式[/b]
假如有一个执行起来需要花费一些时间的方法,为了省去不必要的等待执行结果出来,继续做别的事情,则可以事先获取一个“提货单”即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 {
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 future = new FutureTask(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


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

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

模拟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


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

利用Master-Worker模式做1-100的立方和:
public class Worker implements Runnable {
protected Queue workQueue;
protected Map resultMap;

public void setWorkQueue(Queue workQueue) {
this.workQueue = workQueue;
}

public void setResultMap(Map 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 workQueue = new ConcurrentLinkedQueue();
protected Map threadMap = new HashMap();
protected Map resultMap = new ConcurrentHashMap();

public boolean isComplete() {
for(Map.Entry 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 getResultMap() {
return resultMap;
}

public void execute() {
for(Map.Entry 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 resultMap = master.getResultMap();
while(resultMap.size() > 0 || !master.isComplete()) {
Set 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)