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

来源:互联网 发布:linux 查看文件行数 编辑:程序博客网 时间:2024/05/16 17:37

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;}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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() {//将消息委托给另外一个线程去处理@Overridepublic 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) {}}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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();}@Overridepublic 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.");}@Overridepublic 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@Overridepublic 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;@Overridepublic void run() {try {while (!isShutdown) {doWork();}} catch (InterruptedException e) {} finally {doShutdown();}}public void shutdownReqeust() {this.isShutdown = true;//将shutDown标识设为trueinterrupt();//仅置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);}@Overridepublic 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.  线程安全的另种实现
0 0
原创粉丝点击