多线程设计模式读书笔记(一)

1. Single Thread Execution Pattern

1. 概念  

该Pattern用来限制多个线程同时对share resource的访问只让一个线程访问,一般通过synchronzied或lock来完成。

2. demo

Gate类(ShareResource),多线程共同访问。

public class Gate {
	private int counter = 0;
	private String name = "Nobody";
	private String address = "Nowhere";

	public synchronized void pass(String name, String address) {
		this.counter++;
		this.name = name;
		this.address = address;
		check();
	}

	public synchronized String toString() {
		return "No. " + counter + " name: " + name + ", address: " + address;
	}

	private void check() {
		if (name.charAt(0) != address.charAt(0)) {
			System.out.println("******BROKEN*******" + toString());
		}
	}
}


UserThread类
public class UserThread extends Thread {
	private final Gate gate;
	private final String myname;
	private final String myaddress;

	public UserThread(Gate gate, String myname, String myaddress) {
		this.gate = gate;
		this.myname = myname;
		this.myaddress = myaddress;
	}

	public void run() {
		System.out.println(this.myname + "Begin");
		while (true) {
			gate.pass(this.myname, myaddress);
		}
	}
}


Main测试程序
public class Main {
	public static void main(String[] args) {
		Gate gate = new Gate();
		new UserThread(gate, "Alice", "Alaska").start();
		new UserThread(gate, "Bobby", "Brazil").start();
		new UserThread(gate, "Chris", "Canada").start();
	}
}

3. 注意事项

  • 使用场景
当多个线程同时访问共享资源,并可能进行修改,而修改的结果会影响其他线程的运行结果时,就需要用该模式。
  • 性能
一般来说,该模式会使程序性能降低的原因有两点。一是不管synchronzied或者lock,获取锁对象都需要耗费时间。二是当某线程获得锁对象进入临界区,其他的线程

都需要等待该线程释放锁对象,这个状况称之为冲突。当冲突发生时,线程等待的时间就会使整个程序的心跟那个下降。故应该尽可能的缩小临界区范围,以减少出现线程冲突

的机会, 可抑制性能的降低。

2. Immutable Pattern

1. 概念
在Immutable Pattern中,有着能够保证实例状态绝不会改变的类(immutable类)。因为访问这个实例时,可以省去使用共享互斥机制所会浪费的时间,故若能妥善运

用,将能提高程序的性能。String类,基本类型的封装类(Integer, Long等)就是一个immutable的类。

2. demo

Person类,final类型,不可变
public final class Person {
	private final String name;
	private final String address;

	public Person(String name, String address) {
		this.name = name;
		this.address = address;
	}

	public String getName() {
		return this.name;
	}

	public String getAddress() {
		return this.address;
	}

	public String toString() {
		return "[ Person: name =" + name + ", address = " + address + " ]";
	}
}

Thread类
public class PrintPersonThread extends Thread {
	
	private Person person;

	public PrintPersonThread(Person persion) {
		this.person = person;
	}

	public void run() {
		while (true) {
			System.out.println(Thread.currentThread().getName() + " prints "
					+ person);
		}
	}
}

Main测试
public class Main {
	public static void main(String[] args){
		Person alice = new Person("Alice", "Alaska");
		new PrintPersonThread(alice).start();
		new PrintPersonThread(alice).start();
		new PrintPersonThread(alice).start();
	}
}

3. 注意事项

  • 使用场景
1. 当实例产生后,状态不再变化 
2. 实例需要共享,且访问很频繁
  • 性能
因不用获取锁和减少了冲突,善于该模式能有效提升程序的性能。

3. Guarded Suppension Pattern

1. 概念
当线程执行某个操作时,发现条件并不满足,就要求要执行该操作的线程等待挂起。

2. demo

public class Request {

	private String name;

	public Request(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	@Override
	public String toString() {
		return "[ Request " + name + " ]";
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: RequestQueue.java
 * 类描述: 消息存储类
 * </pre>
 */
public class RequestQueue {

    final private LinkedList<Request> queue = new LinkedList<Request>();

    public synchronized void putRequest(Request request) {//生产者生产消息后通知消费者消费
        this.queue.addLast(request);
        notifyAll();
    }

    public synchronized Request getRequest() {
        while (this.queue.size() <= 0) {//如果执行条件不满足,则线程wait
           try {
                wait();
            }catch (InterruptedException e) {
            }
        }
        return queue.removeFirst();
    }
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ServerThread.java
 * 类描述:生产者线程,生成消息并存储到消息存储队列中 
 * </pre>
 */
public class ServerThread extends Thread {

	private Random random;

	private RequestQueue queue;

	public ServerThread(RequestQueue queue, String name, long seed) {
		super(name);
		this.queue = queue;
		random = new Random(seed);
	}

	@Override
	public void run() {
		for (int i = 0; i < 10000; i++) {
			Request request = queue.getRequest();
			System.out.println(Thread.currentThread().getName() + " handles " + request);
			try {
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ClientThread.java
 * 类描述: 消费者线程,从消息存储队列中消费消息,若无消息消费,则等待。
 * </pre>
 */
public class ClientThread extends Thread {

	private Random random;

	private RequestQueue requestQueue;

	public ClientThread(RequestQueue requestQueue, String name, long seed) {
		super(name);
		this.requestQueue = requestQueue;
		this.random = new Random(seed);
	}

	@Override
	public void run() {
		for (int i = 0; i < 10000; i++) {
			Request request = new Request("No." + i);
			System.out.println(Thread.currentThread().getName() + " requests " + request);
			this.requestQueue.putRequest(request);
			try {
				Thread.sleep(this.random.nextInt(1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

public class Main {
	public static void main(String[] args) {
		RequestQueue queue = new RequestQueue();
		ServerThread serverThread = new ServerThread(queue, "ServerThread", 21563L);
		ClientThread clientThread = new ClientThread(queue, "ClientThread", 24871L);
		serverThread.start();
		clientThread.start();
	}
}

3. 注意事项

  • 使用场景
生产者消费者模式,异步执行的一种实现。

4.  Balking Pattern

1.  概念

Balking Pattern与Guarded Suppension Pattern类似,区别在于当线程执行某一操作发现条件不满足时,是立即返回,中断执行,而不是等待条件满足。

2.  demo

public class Data {

	private final String filename;

	private String content;

	private boolean changed;

	public Data(String filename, String content) {
		this.filename = filename;
		this.content = content;
		this.changed = true;
	}

	/**
	 * 修改文件内容
	 * @param content
	 */
	public synchronized void change(String content) {
		this.content = content;
		this.changed = true;
	}

	/**
	 * 保存修改后的数据,保存到硬盘上
	 */
	public synchronized void save() {
		while (!this.changed) {//如果发现文件没有被修改,则不做保存动作
			return;
		}
		doSave();
		this.changed = false;
	}

	private void doSave() {
		System.out.println(Thread.currentThread().getName()
				+ "calls doSave, content = " + this.content);
		File file = new File(filename);
		FileWriter writer = null;
		try {
			writer = new FileWriter(file, true);
			writer.write(this.content);
		} catch (IOException e) {

		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ChangerThread.java
 * 类描述: 改变文件内容线程
 * </pre>
 */
public class ChangerThread extends Thread {

	private Data data;

	private Random random = new Random();

	public ChangerThread(String name, Data data) {
		super(name);
		this.data = data;
	}

	@Override
	public void run() {
		int i = 0;
		while (true) {
			i++;
			String content = "No." + i;
			this.data.change(content);
			try {
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
			this.data.save();
		}
	}
}

/**
 * <pre>
 * 项目名: ThreadPattern
 * 类名: SaverThread.java
 * 类描述: 保存文件线程
 * </pre>
 */
public class SaverThread extends Thread {

	private Data data;

	private Random random = new Random();

	public SaverThread(String name, Data data) {
		super(name);
		this.data = data;
	}

	@Override
	public void run() {
		while (true) {
			this.data.save();
			try {
				Thread.sleep(this.random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}
}

/**
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Main.java
 * 类描述: 测试
 * </pre>
 */
public class Main {
	public static void main(String[] args) {
		Data data = new Data("data.txt", "(empty)");
		new SaverThread("SaverThread", data).start();
		new ChangerThread("ChangerThread", data).start();
	}
}

3. 注意事项

  • 使用场景
1.  不需要可以去执行的时候,如在上面的demo中,如果文件内容没有被修改,则不需要执行保存动作, 可提高程序性能。
2.  不想等待条件满足时,可提高程序的响应时间。
3.  某操作只需要执行一次时,如初始化。

5.  Producer - Customer Pattern

1. 概念
Producer - Customer Pattern(生产者消费者模式),生产者生产消息,消费者消费消息,二者处理消息的速度可能不一致,那么需要一个缓存区来存放消息。

2. demo

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Data.java
 * 类描述:消息 
 * </pre>
 */
public class Data {

	private String name;

	public Data(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "[ Data name = " + this.name + " ]";
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Channel.java
 * 类描述: 消息缓冲区,默认大小100,可以通过构造函数定制channel的大小。channel为FIFO模型
 * </pre>
 */
public class Channel {

	private final LinkedList<Data> buffer = new LinkedList<Data>();

	private int bufferSize = 100;

	public Channel() {
		super();
	}

	public Channel(int channelSize) {
		this.bufferSize = channelSize;
	}

	/**
	 * put数据到channel中,当channel的buffer大小大于或等于指定大小时,方法将进行等待
	 * 
	 * @param data
	 */
	public synchronized void put(Data data) {
		while (buffer.size() >= this.bufferSize) {
			try {
				wait();
			} catch (InterruptedException e) {
			}
		}

		this.buffer.addLast(data);
		System.out.println(Thread.currentThread().getName() + " put data "+ data);
		notifyAll();
	}

	/**
	 * 从channel中获取数据,当channel中没有数据时,进行等待
	 * 
	 * @return
	 */
	public synchronized Data take() {
		while (this.buffer.size() == 0) {
			try {
				wait();
			} catch (InterruptedException e) {
			}
		}
		Data data = this.buffer.removeFirst();
		System.out.println(Thread.currentThread().getName() + " take date " + data);
		notifyAll();
		return data;
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ProducerThread.java
 * 类描述: 生产者线程,生成消息并放入到消息缓冲区中
 * </pre>
 */
public class ProducerThread extends Thread {

	private Channel channel;

	private Random random = new Random();

	private static int dataNo = 0;

	public ProducerThread(String name, Channel channel) {
		super(name);
		this.channel = channel;
	}

	@Override
	public void run() {
		while (true) {
			Data data = new Data("No." + nextDataNo());
			this.channel.put(data);
			try {
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}

	public static synchronized int nextDataNo() {
		return ++dataNo;
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ComsumerThread.java
 * 类描述:消费者线程,从消息缓存区Channel消费消息 
 * </pre>
 */
public class ComsumerThread extends Thread {

	private Channel channel;

	private Random random = new Random();

	public ComsumerThread(String name, Channel channel) {
		super(name);
		this.channel = channel;
	}

	@Override
	public void run() {
		while (true) {
			this.channel.take();
			try {
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}
}

public class MainThread {

    public static void main(String[] args) {
    	
        int channelSize = 1000;
        Channel channel = new Channel(channelSize);

        ProducerThread producer1 = new ProducerThread("Producer1", channel);
        ProducerThread producer2 = new ProducerThread("Producer2", channel);

        ComsumerThread comsumer1 = new ComsumerThread("Comsumer1", channel);
        ComsumerThread comsumer2 = new ComsumerThread("Comsumer2", channel);
        ComsumerThread comsumer3 = new ComsumerThread("Comsumer3", channel);

        producer1.start();
        producer2.start();

        comsumer1.start();
        comsumer2.start();
        comsumer3.start();
    }
}

3. 注意事项

  • 使用场景
经常用作消息中心,异步消费消息,

6. Read - Write Lock Pattern 

1.  概念

Reade-Write Lock Pattern将读取与写入分开来处理。在读取数据之前,必须获取用来读取的锁定。而要写入的时候,则必须获取用来写入的锁定。因为在读取的时候,实

例的状态不会改变,所以,就算有多个线程在同时读取也没有关系。但是,有线程在读取的时候,不能做写入的操作。写入的时候,实例的状态会该别,于是,在有一个线程写

入的时候,其他线程就不可以进行读取或者写入。

一般来说,进行共享互斥会使程序性能变差,但将写入的共享互斥与读取的共享分开来思考,就可以提升程序的性能。

2.  demo

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ReadWriteLock.java
 * 类描述:读写锁 
 * </pre>
 */
public class ReadWriteLock {

	/**
	 * 正在读取的线程数
	 */
	private int readingThreadsNumber;

	/**
	 * 正在写入的线程数(最多为1)
	 */
	private int writingThreadsNumber;

	/**
	 * 等待写入的线程数
	 */
	private int waitingWriteThreadsNumber;

	/**
	 * 是否优先写入,true:优先写入;false:优先读取
	 */
	private boolean preferWriter = true;

	public synchronized void readLock() throws InterruptedException {
		// 如果有线程正在写入或者优先写入时,有线程正在等待写入,读取线程则等待
		while (this.writingThreadsNumber > 0
				|| (this.preferWriter && this.waitingWriteThreadsNumber > 0)) {
			wait();
		}

		this.readingThreadsNumber++;
	}

	public synchronized void readUnlock() throws InterruptedException {
		this.readingThreadsNumber--;
		this.preferWriter = true;
		notifyAll();
	}

	public synchronized void writeLock() throws InterruptedException {
		this.waitingWriteThreadsNumber++;
		// 如果有线程正在写入或者正在读取,当前写入线程等待
		try {
			while (this.writingThreadsNumber > 0
					|| this.readingThreadsNumber > 0) {
				wait();
			}
		} finally {
			this.waitingWriteThreadsNumber--;
		}

		this.writingThreadsNumber++;
	}

	public synchronized void writeUnlock() throws InterruptedException {
		this.writingThreadsNumber--;
		this.preferWriter = false;
		notifyAll();
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Data.java
 * 类描述:数据存储对象
 * </pre>
 */
public class Data {

	private char[] buffer;

	private ReadWriteLock readWriteLock = new ReadWriteLock();

	public Data(int size) {
		this.buffer = new char[size];
		for (int i = 0; i < size; i++) {
			this.buffer[i] = '*';
		}
	}

	public char[] read() throws InterruptedException {
		try {
			readWriteLock.readLock();
			return doRead();
		} finally {
			readWriteLock.readUnlock();
		}
	}

	public void write(char c) throws InterruptedException {
		try {
			readWriteLock.writeLock();
			doWrite(c);
		} finally {
			readWriteLock.writeUnlock();
		}
	}

	private char[] doRead() {
		char[] newChars = new char[buffer.length];
		System.arraycopy(this.buffer, 0, newChars, 0, this.buffer.length);
		slowly();
		return newChars;
	}

	private void doWrite(char c) {
		for (int i = 0; i < this.buffer.length; i++) {
			this.buffer[i] = c;
			slowly();
		}
	}

	private void slowly() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
		}
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ReaderThread.java
 * 类描述:读线程 
 * </pre>
 */
public class ReaderThread extends Thread {

	private static final Random random = new Random();

	private final Data data;

	public ReaderThread(Data data) {
		this.data = data;
	}

	@Override
	public void run() {
		while (true) {
			try {
				char[] c = data.read();
				System.out.println(Thread.currentThread().getName() + "reads " + String.valueOf(c));
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: WriterThread.java
 * 类描述:写线程 
 * </pre>
 */
public class WriterThread extends Thread {

	private static final Random random = new Random();

	private final Data data;

	private final String filler;

	private int index = 0;

	public WriterThread(Data data, String filler) {
		this.data = data;
		this.filler = filler;
	}

	@Override
	public void run() {
		while (true) {
			char c = nextChar();
			try {
				data.write(c);
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}

	private char nextChar() {
		char c = filler.charAt(index);
		index++;
		if (index > filler.length()) {
			index = 0;
		}

		return c;
	}
}

public class MainThread {

	public static void main(String[] args) {
		int bufferSize = 10;
		Data data = new Data(bufferSize);

		new ReaderThread(data).start();
		new ReaderThread(data).start();
		new ReaderThread(data).start();
		new ReaderThread(data).start();
		new ReaderThread(data).start();
		new ReaderThread(data).start();
		new ReaderThread(data).start();

		String filler1 = "abcdefghjklmnopqrstuvwxyz";
		String filler2 = "ABCDEFGHJKLMNOPQRSTUVWXYZ";
		new WriterThread(data, filler1).start();
		new WriterThread(data, filler2).start();

	}

}

3. 注意事项

  • 使用场景
1. 利用同时读不会冲突的特性,提高程序的性能
2. 适合读取操作十分频繁
3. 适合读取比写入次数频繁

7. Thread-Per-Message Pattern

1.  概念

Thread-Per-Message Pattern指每个消息一个线程,即对于每个命令或请求,分配一个线程去执行。

2.  demo

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Helper.java
 * 类描述: 消息执行线程
 * </pre>
 */
public class Helper {

	public void handle(int count, char c) {
		System.out.println("handle(" + count + ", " + c + ") BEGIN");
		for (int i = 0; i < count; i++) {
			System.out.print(c);
			slowly();
		}
		System.out.println("");
		System.out.println("handle( " + count + ", " + c + ") END");
	}

	private void slowly() {
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
		}
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Host.java
 * 类描述: 消息处理线程(委托给另一个线程去处理)
 * </pre>
 */
public class Host {

	private final Helper helper = new Helper();

	public void request(final int count, final char c) {
		System.out.println("reqeust (" + count + ", " + c + ") BEGIN");
		new Thread() {//将消息委托给另外一个线程去处理
			@Override
			public void run() {
				helper.handle(count, c);
			}
		}.start();
		System.out.println("reqeust (" + count + ", " + c + ") END");
	}
}

public class MainThread {
	public static void main(String[] args) {
		System.out.println("main Begin");
		Host host = new Host();
		host.request(10, 'a');
		host.request(20, 'b');
		host.request(30, 'c');

		System.out.println("main End");
	}
}

3.  注意事项

  • 使用场景
1.  提高相应性, 降低延迟时间
2. 适合在操作顺序无所谓时使用
3. 不需要返回之的时候
4.  应用在服务器的制作,将服务端接受消息的线程和处理消息的线程分开

8. Worker Thread Pattern

1. 概念
Worker Threade Pattern指工作线程会依次抓意见工作来处理,当没有工作可作时,工作线程会停下来等待新的工作过来。Worker Thread 也被称为是Backgound 

Thread(背景线程), 另外,也有人把管理工作线程的地方,称为 Thread Pool (线程池)。

2. demo

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Request.java
 * 类描述: 消息对象
 * </pre>
 */
public class Request {

	private final String name;

	private final int number;

	private final static Random random = new Random();

	public Request(String name, int number) {
		this.name = name;
		this.number = number;
	}

	public void request() {
		System.out.println(Thread.currentThread().getName() + " " + toString());
		try {
			Thread.sleep(random.nextInt(1000));
		} catch (InterruptedException e) {
		}
	}

	@Override
	public String toString() {
		return "[ Reqeust name = " + name + ", number = " + number + " ]";
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: Channel.java
 * 类描述: 消息存储容器
 * </pre>
 */
public class Channel {

	private final LinkedList<Request> buffers = new LinkedList<Request>();

	private static final int bufferSize = 100;

	public synchronized void put(Request request) throws InterruptedException {
		while (this.buffers.size() >= bufferSize) {
			wait();
		}
		this.buffers.addLast(request);
		notifyAll();
	}

	public synchronized Request take() throws InterruptedException {
		while (this.buffers.size() == 0) {
			wait();
		}
		Request request = this.buffers.removeFirst();
		notifyAll();
		return request;
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: ProducerThread.java
 * 类描述: 生产者线程,将生产消息并将消息放到消息容器中
 * </pre>
 */
public class ProducerThread extends Thread {

	private final Channel channel;

	private final static Random random = new Random();

	public ProducerThread(String name, Channel channel) {
		super(name);
		this.channel = channel;
	}

	@Override
	public void run() {
		int i = 0;
		while (true) {
			Request request = new Request(getName(), ++i);
			try {
				this.channel.put(request);
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
			}
		}
	}
}

/**
 * 
 * <pre>
 * 项目名: ThreadPattern
 * 类名: WorkerThread.java
 * 类描述:工作线程,从消息存储器中拿到消息处理, 没有则等待
 * </pre>
 */
public class WorkerThread extends Thread {

	private Channel channel;

	public WorkerThread(String name, Channel channel) {
		super(name);
		this.channel = channel;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Request request = this.channel.take();
				request.request();
			} catch (InterruptedException e) {
			}
		}
	}
}

/**
 * <pre>
 * 项目名: ThreadPattern
 * 类名: WorkerTheradPool.java
 * 类描述: 工作线程池
 * </pre>
 */
public class WorkerTheradPool {

	private WorkerThread[] threadPool;

	public WorkerTheradPool(int threads, Channel channel) {
		this.threadPool = new WorkerThread[threads];//定义一个工作线程组(线程池)
		for (int i = 0; i < threads; i++) {
			threadPool[i] = new WorkerThread("WorkerThread-" + (i + 1), channel);
		}
	}

	public void startWorkers() {
		for (int i = 0; i < this.threadPool.length; i++) {
			threadPool[i].start();
		}
	}
}

public class Main {

	public static void main(String[] args) {
		int threads = 5;
		Channel channel = new Channel();
		WorkerTheradPool pool = new WorkerTheradPool(threads, channel);
		new ProducerThread("Alice", channel).start();
		new ProducerThread("Bobby", channel).start();
		new ProducerThread("Chris", channel).start();
		pool.startWorkers();
	}
}

3. 注意事项

  • 使用场景
1. 启动线程是个很繁杂的工作,可以先把线程创建好,用的时候再直接拿来用。
2. 控制承载量(即可以提供服务的线程数量),当任务繁重是可以扩大工作者线程数量,反之,可以减少。

9. Future Pattern

1. 概念
Futuren Pattern是指获取Futuren的线程,会在事后再去获取执行的结果。就好像拿提货单去领取蛋糕一样。如果已经有执行结果了, 就可以马上拿到数据;如果执行结果

还没有好,则继续等待执行结果出现为止。

2. demo

public interface Data {
	public String getContent();
}

public class FutureData implements Data {

	private RealData realData;

	private boolean ready = false;

	public synchronized void setRealData(RealData realData) {
		if (ready) {
			return;
		}
		this.realData = realData;
		this.ready = true;
		notifyAll();
	}

	@Override
	public synchronized String getContent() {
		while (!ready) {//如果结果还没处理好,则等待
			try {
				wait();
			} catch (InterruptedException e) {
			}
		}
		return this.realData.getContent();
	}
}

public class RealData implements Data {

	private String content;

	public RealData(int count, char c) {
		System.out.println("making RealData(" + count + ", " + c + ") Begin.");
		//处理获取结果
		char[] buffer = new char[count];
		for (int i = 0; i < count; i++) {
			buffer[i] = c;
			slowly();
		}
		this.content = String.valueOf(buffer);
		System.out.println("making RealData(" + count + ", " + c + ") End.");
	}

	@Override
	public String getContent() {
		return this.content;
	}

	private void slowly() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
		}
	}
}

public class Host {

	public Data handle(final int count, final char c) {

		System.out.println("handle ( " + count + ", " + c + ") Begin.");
		
		final FutureData futureData = new FutureData();//创建Future对象
		new Thread() {//将处理消息获取消息的工作交个另外一个线程去处理,参考Thread Per Message Pattern
			@Override
			public void run() {
				RealData realData = new RealData(count, c);
				futureData.setRealData(realData);
			}
		}.start();

		System.out.println("handle ( " + count + ", " + c + ") End.");
		return futureData;
	}
}

public class Main {

	public static void main(String[] args) {
		System.out.println("main Begin.");
		Host host = new Host();
		Data data1 = host.handle(10, 'a');
		Data data2 = host.handle(20, 'b');
		Data data3 = host.handle(30, 'c');

		System.out.println("main other job Begin.");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
		}
		System.out.println("main other job End.");

		System.out.println("data1 = " + data1.getContent());
		System.out.println("data2 = " + data2.getContent());
		System.out.println("data3 = " + data3.getContent());

		System.out.println("main End.");
	}
}

3. 注意事项

  • 使用场景
将任务交由另外一个线程去异步处理,自己能继续做自己的工作,即响应性不会降低,并且在工作线程处理完之后,还能获取处理结果。

10.  Two-Phase Termination Pattern

1. 概念
我们将线程进行平常的处理的状态称为【作业中】, 当希望结束这个线程时,则送出【终止请求】。 接着这个线程,并不会马上结束, 而会开始处理必要的刷新工作。这

个状态称为【终止处理中】。 从【作业中】改变为【终止处理中】是第一个阶段。【终止处理中】的状态时,不会进行平常的操作,虽然线程还在运行,但是进行的是终止处

理。知道终止处理结束后,才真正结束线程。【终止处理中】的操作结束,是第二阶段。

可用来优雅的终止线程,一是安全的终止(安全性), 二是一定会进行终止处理(生命性), 三是在送出终止请求后,尽快的处理(响应性)。

2. demo

public class CountupThread extends Thread {

	private boolean isShutdown = false;

	private int count = 0;

	@Override
	public void run() {

		try {
			while (!isShutdown) {
				doWork();
			}
		} catch (InterruptedException e) {
		} finally {
			doShutdown();
		}

	}

	public void shutdownReqeust() {
		this.isShutdown = true;//将shutDown标识设为true
		interrupt();//仅置shutdown标识不正确,因为此时线程可能正在sleep或者wait,这样虽然sleep结束后,再来停止线程,但这样响应性就差饿了点。
	}

	private void doShutdown() {
		System.out.println("doShutdown: current count is " + this.count);
	}

	private void doWork() throws InterruptedException {
		System.out.println("curren count is " + ++count);
		Thread.sleep(500);
	}
}

public class MainThread {
	public static void main(String[] args) {
		System.out.println("main Begin.");

		CountupThread countupThread = new CountupThread();
		countupThread.start();

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
		}
		System.out.println("main : shutdown request.");
		countupThread.shutdownReqeust();

		System.out.println("main : join");

		// 等待线程结束
		try {
			countupThread.join();
		} catch (InterruptedException e) {
		}
		System.out.println("main End.");
	}
}

3. 注意事项

  • 使用场景
1. 不可以使用Thread类的stop方法,stop会强制停止线程,就肯能丧失安全性,因为说不定线程刚好在做临界区。
  2. 进行繁重的处理前,先检查终止请求,这样一来,可使得程序的响应性提高。

11.  Thread-Specific Storage Pattern

1. 概念
Thread-Specific Storage Pattern就是线程独有的存储库,针对每个线程提供的内存空间,独立于线程之外。ThreadLocal的实例可以想象成一种集合框架,该类的实例只

有一个,实现是用Map<Key, Value>, Key为当前线程的id,Value为设置的值。

2. demo

public class Log {

	//存储各个线程的Log日志,ThreadLocal<T>, 实现是一个map, key为当前线程id,value为T
    private static final ThreadLocal<TSLog> tsLogCollection = new ThreadLocal<TSLog>();

    public static void println(String s) {
        getTSLog().printWrite(s);
    }

    public static void close() {
        getTSLog().close();
    }

    private static TSLog getTSLog() {
        TSLog tsLog = tsLogCollection.get();
        // 如果线程时第一次调用,新建立新文件并注册log
        if (tsLog == null) {
            tsLog = new TSLog(Thread.currentThread().getName() + "-log.txt");
            tsLogCollection.set(tsLog);
        }
        return tsLog;
    }
}

public class TSLog {

	private PrintWriter writer;

	public TSLog(String filename) {
		try {
			this.writer = new PrintWriter(filename);
		} catch (FileNotFoundException e) {
		}
	}

	public void printWrite(String s) {
		writer.println(s);
	}

	public void close() {
		writer.println("===========End of log===========");
		writer.close();
	}
}

public class ClientThread extends Thread {

	public ClientThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		System.out.println(getName() + " Begin.");

		for (int i = 0; i < 10; i++) {
			Log.println("i = " + i);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
			}
		}
		Log.close();
		System.out.println(getName() + " End.");
	}
}

public class MainThread {
	public static void main(String[] args) {
		new ClientThread("Alice").start();
		new ClientThread("Bobby").start();
		new ClientThread("Chris").start();
	}
}

3. 注意事项

  • 使用场景
1.  存放线程特有信息的地方
2.  线程安全的另种实现

转载于:https://www.cnblogs.com/marcotan/p/4256850.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值