《Java7并发编程实战手册》读书笔记
一、线程管理
1、线程的创建和运行
创建线程的2种方式:
继承Thread类,并覆盖run()方法
创建一个实现Runnable接口的类。使用带参数的Thread构造器来创建Thread对象
每个Java程序都至少有一个执行线程。当运行程序的时候,JVM将启动这个执行线程来调用程序的main()方法
当一个程序的所有非守护(non-daemon)线程都运行完成的时候,这个Java程序将结束
如果初始现场(执行main()方法的线程)结束了,其余的线程仍将继续执行直到它们运行结束
如果某一个线程调用了System.exit()指令来结束程序的执行,所有的线程都将结束
2种创建方式例子:
public class Calculator1 extends Thread { private int number; public Calculator1(int number) { this.number = number; } @Override public void run() { for(int i=1; i<=10; i++) { System.out.printf("1: %s: %d * %d = %d\n", Thread.currentThread().getName(), number, i, i*number); } } } public class Calculator2 implements Runnable { private int number; public Calculator2(int number) { this.number = number; } @Override public void run() { for(int i=1; i<=10; i++) { System.out.printf("2: %s: %d * %d = %d\n", Thread.currentThread().getName(), number, i, i*number); } } } public class Main { public static void main(String[] args) { for(int i=1; i<=10; i++) { Calculator1 calculator1 = new Calculator1(i); calculator1.start(); Calculator2 calculator2 = new Calculator2(i); Thread thread = new Thread(calculator2); thread.start(); } } }
2、线程信息的获取和设置
Thread类的一些属性:
ID:保存了线程的唯一标示符
Name:保存了线程名称
Priority:保存了线程对象的优先级。从低到高:1-10。不推荐去改变线程的优先级
Status:保存了线程的状态。线程的状态有6种:new、runnable、blocked、waiting、time waiting或terminated
Thread类的属性储存了线程的所有信息,线程的ID和状态是不允许被修改的,线程类没有提供setId()和setStatus()方法来修改它们
修改线程优先级、输出线程状态例子:
public class Calculator implements Runnable { private int number; public Calculator(int number) { this.number = number; } @Override public void run() { for(int i=1; i<=10; i++) { System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(), number, i, i*number); } } } public class Main { public static void main(String[] args) throws IOException { Thread threads[] = new Thread[10]; Thread.State status[] = new Thread.State[10]; for(int i=0; i<10; i++) { threads[i] = new Thread(new Calculator(i)); if((i%2)==0) { threads[i].setPriority(Thread.MAX_PRIORITY); } else { threads[i].setPriority(Thread.MIN_PRIORITY); } threads[i].setName("Thread " + i); } for(int i=0; i<10; i++) { System.out.println("Main: Status of Thread " + i + ": " + threads[i].getState()); status[i] = threads[i].getState(); } for(int i=0; i<10; i++) { threads[i].start(); } boolean finish = false; while(!finish) { for(int i=0; i<10; i++) { if(threads[i].getState() != status[i]) { writeThreadInfo(threads[i], status[i]); status[i] = threads[i].getState(); } } } } private static void writeThreadInfo(Thread thread, State state) { System.out.printf("Main: Id %d - %s\n", thread.getId(), thread.getName()); System.out.printf("Main: Priority: %d\n", thread.getPriority()); System.out.printf("Main: Old State: %s\n", state); System.out.printf("Main: New State: %s\n", thread.getState()); System.out.printf("Main: ************************\n"); } }
3、线程的中断
Java提供了中断机制,可以使用它阿里结束一个线程。这种机制要求线程检查它是否被中断了,然后决定是不是响应这个中断请求。线程允许忽略中断请求并继续执行
Thread类有一个表明线程被中断与否的属性,它存放的是布尔值。线程的interrupt()方法被调用时,这个属性就会被设置为true。isInterruped()方法只是返回这个属性的值
Thread类还有一个静态方法interrupted()也可以检测线程是否已被中断,它还能设置interrupted的属性为false。更推荐使用isInterruped()
中断线程例子:
public class PrimeGenerator extends Thread { @Override public void run() { long number = 1L; while(true) { if(isPrime(number)) { System.out.printf("Number %d is Prime\n", number); } if(isInterrupted()) { System.out.printf("The Prime Generator has been Interrupted"); return; } number ++; } } private boolean isPrime(long number) { if(number <= 2) { return true; } for(long i=2; i<number; i++) { if((number % i) == 0) { return false; } } return true; } } public class Main { public static void main(String[] args) { Thread task = new PrimeGenerator(); task.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } task.interrupt(); } }
4、线程中断的控制
InterruptedException异常控制线程中断例子:
public class FileSearch implements Runnable { private String initPath; private String fileName; public FileSearch(String initPath, String fileName) { this.initPath = initPath; this.fileName = fileName; } @Override public void run() { File file = new File(initPath); if(file.isDirectory()) { try { directoryProcess(file); } catch (InterruptedException e) { System.out.printf("%s: The search has been interrupted", Thread.currentThread().getName()); } } } private void directoryProcess(File file) throws InterruptedException { File list[] = file.listFiles(); if(list != null) { for(int i=0; i<list.length; i++) { if(list[i].isDirectory()) { directoryProcess(list[i]); } else { fileProcess(list[i]); } } } if(Thread.interrupted()) { throw new InterruptedException(); } } private void fileProcess(File file) throws InterruptedException { if(file.getName().equals(fileName)) { System.out.printf("%s: %s\n", Thread.currentThread().getName(), file.getAbsolutePath()); } if(Thread.interrupted()) { throw new InterruptedException(); } } } public class Main { public static void main(String[] args) { FileSearch searcher = new FileSearch("c:\\", "233.txt"); Thread thread = new Thread(searcher); thread.start(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { thread.interrupt(); } thread.interrupt(); } }
5、线程的休眠和恢复
sleep()方法例子:
public class FileClock implements Runnable { @Override public void run() { for(int i=0; i<10; i++) { System.out.printf("%s\n", new Date()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.printf("The FileClock has been interrupted\n"); } } } } public class FileMain { public static void main(String[] args) { FileClock clock = new FileClock(); Thread thread = new Thread(clock); thread.start(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); } }
6、等待线程的终止
当一个线程对象的join方法被调用时,调用它的线程将被挂起,直到这个线程对象完成它的任务
join(long milliseconds):thread运行已经完成或者毫秒参数已经到达,都将继续运行
等待线程例子:
public class DataSourcesLoader implements Runnable { @Override public void run() { System.out.printf("Beginning data sources loading: %s\n", new Date()); try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Data sources loading has finished: %s\n", new Date()); } } public class NetworkConnectionsLoader implements Runnable { @Override public void run() { System.out.printf("Beginning network connections loading: %s\n", new Date()); try { TimeUnit.SECONDS.sleep(6); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Network Connections loading has finished: %s\n", new Date()); } } public class Main { public static void main(String[] args) { DataSourcesLoader dataLoader = new DataSourcesLoader(); Thread thread1 = new Thread(dataLoader, "DataSourceTHread"); NetworkConnectionsLoader cnLoader = new NetworkConnectionsLoader(); Thread thread2 = new Thread(cnLoader, "NetworkConnectionsLoader"); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Configuration has been loaded: %s\n", new Date()); } }
7、守护线程的创建和运行
Java中有一种特殊的线程叫做守护(Daemon)线程,优先级很低
守护线程通常被用来作为同一程序中普通线程(用户线程)的服务提供者,它们通常是无限循环的,以等待服务请求或者执行线程任务
它们不能做重要的工作,因为不知道什么时候能够获取CPU时钟,并且没有其他线程运行的时候,守护线程随时可能结束
典型的守护线程是Java的垃圾回收器(Garbge Collector)
setDaemon()方法只能在start()方法被调用之前设置,线程开始运行后就不能修改守护状态,isDaemon()方法来检查一个线程是不是守护线程
守护线程管理线程队列例子:
public class Event { private Date date; private String event; public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getEvent() { return event; } public void setEvent(String event) { this.event = event; } } public class WriterTask implements Runnable { private Deque<Event> deque; public WriterTask(Deque<Event> deque) { this.deque = deque; } @Override public void run() { for(int i=1; i<100; i++) { Event event = new Event(); event.setDate(new Date()); event.setEvent(String.format("The thread %s has generated an event", Thread.currentThread().getId())); deque.addFirst(event); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class CleanerTask extends Thread { private Deque<Event> deque; public CleanerTask(Deque<Event> deque) { this.deque = deque; } @Override public void run() { while(true) { Date date = new Date(); clean(date); } } private void clean(Date date) { long difference; boolean delete; if(deque.size() == 0) { return; } delete = false; do { Event e = deque.getLast(); difference = date.getTime() - e.getDate().getTime(); if(difference > 10000) { System.out.printf("Cleaner: %s\n", e.getEvent()); deque.removeLast(); delete = true; } } while(difference > 10000); if(delete) { System.out.printf("Cleaner: size of the queue: %d\n", deque.size()); } } } public class Main { public static void main(String[] args) { Deque<Event> deque = new ArrayDeque<Event>(); WriterTask writer = new WriterTask(deque); for(int i=0; i<3; i++) { Thread thread = new Thread(writer); thread.start(); } CleanerTask cleaner = new CleanerTask(deque); cleaner.start(); } }
8、线程中不可控异常的处理
Java中的两种异常:
非运行时异常(Checked Exception):这种异常必须在方法生命的throws语句指定,或者在方法体内捕获。例如:IOException和ClassNotFoundException
运行时异常(Unchecked Exception):这种异常不必在方法声明中指定,也不需要在方法体中捕获。例如:NumberFormatException
run()方法不支持throws语句,所以当线程对象的run()犯法抛出非运行异常时,我们必须捕获并处理它们
一个线程抛出了异常并且没有被捕获时(这种情况只可能是运行时异常),JVM检查这个线程是否被预置了未捕获异常处理器,如果找到JVM将调用线程对象的这个方法,并将线程对象和异常作为传入参数
静态方法setDefaultUncaughtExceptionHandler(),为所有的线程对象创建了一个异常处理器
当线程抛出一个未捕获到的异常时,JVM先查找线程对象的未捕获异常处理器,再找所在的线程组的,再找默认的
线程对象里捕获和处理运行时异常的机制例子:
public class ExceptionHandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.printf("An exception has been captured\n"); System.out.printf("Thread: %s\n", t.getId()); System.out.printf("Exception: %s: %s\n", e.getClass().getName(), e.getMessage()); System.out.printf("Stack Trace: \n"); e.printStackTrace(); System.out.printf("Thread status: %s\n", t.getState()); } } public class Task implements Runnable { @Override public void run() { int numero = Integer.parseInt("TTT"); } } public class Main { public static void main(String[] args) { Task task = new Task(); Thread thread= new Thread(task); thread.setUncaughtExceptionHandler(new ExceptionHandler()); thread.start(); } }
9、线程局部变量的使用
有时对象的属性不需要被所有线程共享,Java并发API提供了一个线程局部变量机制(Thread-Local Variable),具有很好的性能
线程局部变量的initialValue()方法在第一次访问线程局部变量时被调用,remove()方法用来删除已经储存的值
InheritableThreadLocal类,如果一个线程是从其他某个线程中创建的,这个类将提供继承的值。可以使用childValue()方法初始化子线程在线程局部变量中的值,使用父线程在线程局部变量中的值作为传入参数
public class UnsafeTask implements Runnable{ private Date startDate; @Override public void run() { startDate = new Date(); int time = (int)Math.rint(Math.random()*10); System.out.printf("Starting Thread: %s: %s 等待%d秒\n", Thread.currentThread().getId(), startDate, time); try { TimeUnit.SECONDS.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Thread Finished: %s: %s\n", Thread.currentThread().getId(), startDate); } } public class SafeTask implements Runnable { private static ThreadLocal<Date> startDate = new ThreadLocal<Date>() { protected Date initialValue() { return new Date(); } }; @Override public void run() { int time = (int)Math.rint(Math.random()*10); System.out.printf("Starting Thread: %s: %s 等待%d秒\n", Thread.currentThread().getId(), startDate.get(), time); try { TimeUnit.SECONDS.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Thread Finished: %s: %s\n", Thread.currentThread().getId(), startDate.get()); } } public class Core { public static void main(String[] args) { SafeTask task = new SafeTask(); for(int i=0; i<10; i++) { Thread thread = new Thread(task); thread.start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } }
10、线程的分组
Java提供ThreadGroup类表示一组线程。线程组可以包含线程对象,也可以包含其他的线程组对象,它是一个树形结构
public class Result { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class SearchTask implements Runnable { private Result result; public SearchTask(Result result) { this.result = result; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.printf("Thread %s: Start\n", name); try { doTask(); result.setName(name); } catch (InterruptedException e) { System.out.printf("Thread %s: Interrupted\n", name); return; } System.out.printf("Thread %s: End\n", name); } private void doTask() throws InterruptedException { Random random = new Random((new Date()).getTime()); int value = (int)(random.nextDouble()*100); System.out.printf("Thread %s: %d\n", Thread.currentThread().getName(), value); TimeUnit.SECONDS.sleep(value); } } public class Main { public static void main(String[] args) { ThreadGroup threadGroup = new ThreadGroup("Searcher"); Result result = new Result(); SearchTask searchTask = new SearchTask(result); for(int i=0; i<5; i++) { Thread thread = new Thread(threadGroup, searchTask); thread.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Number of THreads: %d\n", threadGroup.activeCount()); System.out.printf("Information about the Thread Group\n"); threadGroup.list(); Thread[] threads = new Thread[threadGroup.activeCount()]; threadGroup.enumerate(threads); for(int i=0; i<threadGroup.activeCount(); i++) { System.out.printf("Thread %s: %s\n", threads[i].getName(), threads[i].getState()); } waitFinish(threadGroup); } private static void waitFinish(ThreadGroup threadGroup) { while(threadGroup.activeCount() > 9) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } }
11、线程组中不可控异常的处理
例子:
package org.sy.lab.Java7并发编程实战.一线程管理.十一线程组中不可控异常的处理; public class MyThreadGroup extends ThreadGroup { public MyThreadGroup(String name) { super(name); } @Override public void uncaughtException(Thread t, Throwable e) { System.out.printf("The thread %s has thown an Exception \n", t.getId()); e.printStackTrace(); System.out.printf("Termination the rest of the Threads\n"); interrupt(); } } public class Task implements Runnable { @Override public void run() { int result; Random random = new Random(Thread.currentThread().getId()); while(true) { result = 1000/((int)(random.nextDouble()*1000)); System.out.printf("%s: %d\n", Thread.currentThread().getId(), result); if(Thread.currentThread().isInterrupted()) { System.out.printf("%d: Interrupted\n", Thread.currentThread().getId()); return; } } } } public class Main { public static void main(String[] args) { MyThreadGroup threadGroup = new MyThreadGroup("MyThreadGroup"); Task task = new Task(); for(int i=0; i<2; i++) { Thread t = new Thread(threadGroup, task); t.start(); } } }
12、使用工厂类创建线程
例子:
public class MyThreadFactory implements ThreadFactory { private int counter; private String name; private List<String> stats; public MyThreadFactory(String name) { counter = 0; this.name = name; stats = new ArrayList<String>(); } @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, name + "-Thread_" + counter); counter++; stats.add(String.format("Created thread %d with name %s on %s\n", t.getId(), t.getName(), new Date())); return t; } public String getStats() { StringBuffer buffer = new StringBuffer(); Iterator<String> it = stats.iterator(); while(it.hasNext()) { buffer.append(it.next()); buffer.append("\n"); } return buffer.toString(); } } public class Task implements Runnable { @Override public void run() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String[] args) { MyThreadFactory factory = new MyThreadFactory("MyThreadFactory"); Task task = new Task(); Thread thread; System.out.printf("Startibg the Threads\n"); for(int i=0; i<10; i++) { thread = factory.newThread(task); thread.start(); } System.out.printf("Factory stats:\n"); System.out.printf("%s\n", factory.getStats()); } }
二、线程同步基础
1、使用synchronized实现同步方法
public class Account { private double balance; public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public synchronized void addAmount(double amount) { double tmp = balance; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } tmp += amount; balance = tmp; } public synchronized void subtractAmount(double amount) { double tmp = balance; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } tmp -= amount; balance = tmp; } } public class Bank implements Runnable { private Account account; public Bank(Account account) { this.account = account; } @Override public void run() { for(int i=0; i<100; i++) { account.subtractAmount(1000); } } } public class Company implements Runnable { private Account account; public Company(Account account) { this.account = account; } @Override public void run() { for(int i=0; i<100; i++) { account.addAmount(1000); } } } public class Main { public static void main(String[] args) { Account account = new Account(); account.setBalance(1000); Company company = new Company(account); Thread companyThread = new Thread(company); Bank bank = new Bank(account); Thread bankThread = new Thread(bank); System.out.printf("Account: Initial Balance: %f\n", account.getBalance()); companyThread.start(); bankThread.start(); try { companyThread.join(); bankThread.join(); System.out.printf("Account: Final Balance: %f\n", account.getBalance()); } catch (InterruptedException e) { e.printStackTrace(); } } }
2、使用非依赖属性实现同步
public class Cinema { private long vacanciesCinema1; private long vacanciesCinema2; private final Object controlCinema1, controlCinema2; public Cinema() { controlCinema1 = new Object(); controlCinema2 = new Object(); vacanciesCinema1 = 20; vacanciesCinema2 = 20; } public boolean sellTickets1(int number) { synchronized (controlCinema1) { if(number < vacanciesCinema1) { vacanciesCinema1 -= number; return true; } else { return false; } } } public boolean sellTickets2(int number) { synchronized (controlCinema2) { if(number < vacanciesCinema2) { vacanciesCinema2 -= number; return true; } else { return false; } } } public boolean returnTickets1(int number) { synchronized (controlCinema1) { vacanciesCinema1 += number; return true; } } public boolean returnTickets2(int number) { synchronized (controlCinema2) { vacanciesCinema2 += number; return true; } } public long getVacanciesCinema1() { return vacanciesCinema1; } public long getVacanciesCinema2() { return vacanciesCinema2; } } public class TicketOffice1 implements Runnable { private Cinema cinema; public TicketOffice1(Cinema cinema) { this.cinema = cinema; } @Override public void run() { cinema.sellTickets1(3); cinema.sellTickets1(2); cinema.sellTickets2(2); cinema.returnTickets1(3); cinema.sellTickets1(5); cinema.sellTickets2(2); cinema.sellTickets2(2); cinema.sellTickets2(2); } } public class TicketOffice2 implements Runnable { private Cinema cinema; public TicketOffice2(Cinema cinema) { this.cinema = cinema; } @Override public void run() { cinema.sellTickets2(2); cinema.sellTickets2(4); cinema.sellTickets1(2); cinema.sellTickets1(1); cinema.returnTickets2(2); cinema.sellTickets1(3); cinema.sellTickets2(2); cinema.sellTickets1(2); } } public class Main { public static void main(String[] args) { Cinema cinema = new Cinema(); TicketOffice1 ticketOffice1 = new TicketOffice1(cinema); Thread thread1 = new Thread(ticketOffice1, "TicketOffice1"); TicketOffice2 ticketOffice2 = new TicketOffice2(cinema); Thread thread2 = new Thread(ticketOffice2, "TicketOffice2"); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Room 1 Vacancies: %d\n", cinema.getVacanciesCinema1()); System.out.printf("Room 2 Vacancies: %d\n", cinema.getVacanciesCinema2()); } }
3、在同步代码中使用条件
并发编程中一个典型的问题是生产者-消费者(Producer-Consumer)问题
Java在Object类中提供了wait()、notify()和notifyAll()方法,线程可以在同步代码块中调用这些方法
public class EventStorage { private int maxSize; private List<Date> storage; public EventStorage() { maxSize = 10; storage = new LinkedList<>(); } public synchronized void set() { while(storage.size() == maxSize) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } storage.add(new Date()); System.out.printf("Set: %d\n", storage.size()); notifyAll(); } public synchronized void get() { while(storage.size() == 0) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Get: %d: %s\n", storage.size(), ((LinkedList<?>) storage).poll()); notifyAll(); } } public class Producer implements Runnable { private EventStorage storage; public Producer(EventStorage storage) { this.storage = storage; } @Override public void run() { for(int i=0; i<100; i++) { storage.set(); } } } public class Consumer implements Runnable { private EventStorage storage; public Consumer(EventStorage storage) { this.storage = storage; } @Override public void run() { for(int i=0; i<100; i++) { storage.get(); } } } public class Main { public static void main(String[] args) { EventStorage storage = new EventStorage(); Producer producer = new Producer(storage); Thread thread1 = new Thread(producer); Consumer consumer = new Consumer(storage); Thread thread2 = new Thread(consumer); thread2.start(); thread1.start(); } }
4、使用锁实现同步
Java提供了同步代码块的另一种机制,基于Lock接口及实现类,比synchronized关键字更强大灵活,有更好的性能
tryLock()方法试图获取锁,如果没有取到就返回false并继续往下执行
Lock接口允许分离读和写操作,允许多个读线程和只有一个写线程
public class PrintQueue { private final Lock queueLock = new ReentrantLock(); public void printJob(Object document) { queueLock.lock(); try { long duration = (long) (Math.random() * 10000); System.out.println(Thread.currentThread().getName() + ": PrintQueue: Printing a Job during " + (duration/1000) + " seconds"); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { queueLock.unlock(); } } } public class Job implements Runnable { private PrintQueue printQueue; public Job (PrintQueue printQueue) { this.printQueue = printQueue; } @Override public void run() { System.out.printf("%s: Going to print a document\n", Thread.currentThread().getName()); printQueue.printJob(new Object()); System.out.printf("%s: The document has been printed\n", Thread.currentThread().getName()); } } public class Main { public static void main(String args[]) { PrintQueue printQueue = new PrintQueue(); Thread thread[] = new Thread[10]; for(int i=0; i<10; i++) { thread[i] = new Thread(new Job(printQueue), "Thread " + i); } for(int i=0; i<10; i++) { thread[i].start(); } } }
5、使用读写锁实现同步数据访问
ReadWriteLock接口和它唯一实现类ReenTrantReadWriteLock,这个类有两个锁,一个是读操作锁(允许多个线程同时访问),另一个是写操作锁(允许一个线程进行写操作,在一个线程执行写操作时,其他线程不能够执行读操作)
public class PricesInfo { private double price1; private double price2; private ReadWriteLock lock; public PricesInfo() { price1 = 1.0; price2 = 2.0; lock = new ReentrantReadWriteLock(); } public double getPrice1() { lock.readLock().lock(); double value = price1; lock.readLock().unlock(); return value; } public double getPrice2() { lock.readLock().lock(); double value = price2; lock.readLock().unlock(); return value; } public void setPrices(double price1, double price2) { lock.writeLock().lock(); this.price1 = price1; this.price2= price2; lock.writeLock().unlock(); } } public class Reader implements Runnable { private PricesInfo pricesInfo; public Reader(PricesInfo priceInfo) { this.pricesInfo = priceInfo; } @Override public void run() { for(int i=0; i<10; i++) { System.out.printf("%s: Price 1: %f\n", Thread.currentThread().getName(), pricesInfo.getPrice1()); System.out.printf("%s: Price 2: %f\n", Thread.currentThread().getName(), pricesInfo.getPrice2()); } } } public class Writer implements Runnable { private PricesInfo pricesInfo; public Writer(PricesInfo pricesInfo) { this.pricesInfo = pricesInfo; } @Override public void run() { for(int i=0; i<3; i++) { System.out.printf("Writer: Attempt to modify the prices.\n"); pricesInfo.setPrices(Math.random() * 10, Math.random()*8); System.out.printf("Writer: prices have been modified.\n"); try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { PricesInfo pricesInfo = new PricesInfo(); Reader readers[] = new Reader[5]; Thread threadsReader[] = new Thread[5]; for(int i=0; i<5; i++) { readers[i] = new Reader(pricesInfo); threadsReader[i] = new Thread(readers[i]); } Writer writer = new Writer(pricesInfo); Thread threadWriter = new Thread(writer); for(int i=0; i<5; i++) { threadsReader[i].start(); } threadWriter.start(); } }
6、修改锁的公平性
Lock类的构造器都含有一个布尔参数fair,默认是false称为非公平模式,如果为true称为公平模式,选择等待时间最长的
适用于lock()和unlock()方法,tyrLock()方法没有将线程置于休眠,不被fair属性影响
public class PrintQueue { private final Lock queueLock = new ReentrantLock(true); public void printJob(Object document) { queueLock.lock(); try { long duration = (long) (Math.random() * 10000); System.out.println(Thread.currentThread().getName() + ": PrintQueue: Printing a Job during " + (duration/1000) + " seconds"); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { queueLock.unlock(); } queueLock.lock(); try { long duration = (long) (Math.random() * 10000); System.out.println(Thread.currentThread().getName() + ": PrintQueue: Printing a Job during " + (duration/1000) + " seconds"); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { queueLock.unlock(); } } } public class Job implements Runnable { private PrintQueue printQueue; public Job (PrintQueue printQueue) { this.printQueue = printQueue; } @Override public void run() { System.out.printf("%s: Going to print a document\n", Thread.currentThread().getName()); printQueue.printJob(new Object()); System.out.printf("%s: The document has been printed\n", Thread.currentThread().getName()); } } public class Main { public static void main(String args[]) { PrintQueue printQueue = new PrintQueue(); Thread thread[] = new Thread[10]; for(int i=0; i<10; i++) { thread[i] = new Thread(new Job(printQueue), "Thread " + i); } for(int i=0; i<10; i++) { thread[i].start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
7、在锁中使用多条件
Condition接口提供了挂起线程和唤起线程的机制
并发编程中的一个典型问题是生产者-消费者(Producer-Consumer)问题,使用一个数据缓冲区,一个或者多个数据生产者(Producer)将数据保存到缓冲区,一个或者多个数据消费者(Consumer)将数据从缓冲区中取走
public class FileMock { private String content[]; private int index; public FileMock(int size, int length) { content = new String[size]; for(int i=0; i<size; i++) { StringBuilder buffer = new StringBuilder(length); for(int j=0; j<length; j++) { int indice = (int)Math.random() * 255; buffer.append((char)indice); content[i] = buffer.toString(); } index = 0; } } public boolean hasMoreLines() { return index < content.length; } public String getLine() { if(this.hasMoreLines()) { System.out.println("Mock: " + (content.length - index)); return content[index++]; } return null; } } public class Buffer { private LinkedList<String> buffer; private int maxSize; private ReentrantLock lock; private Condition lines; private Condition space; private boolean pendingLines; public Buffer(int maxSize) { this.maxSize = maxSize; buffer = new LinkedList<>(); lock = new ReentrantLock(); lines = lock.newCondition(); space = lock.newCondition(); pendingLines = true; } public void insert(String line) { lock.lock(); try { while(buffer.size() == maxSize) { space.wait(); } buffer.offer(line); System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread().getName(), buffer.size()); lines.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public String get() { String line = null; lock.lock(); try { while((buffer.size() == 0) && (hasPendingLines())) { lines.await(); } if(hasPendingLines()) { line = buffer.poll(); System.out.printf("%s: Line Readed: %d\n", Thread.currentThread().getName(), buffer.size()); space.signalAll(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } return line; } public void setPendingLines(boolean pendingLines) { this.pendingLines = pendingLines; } public boolean hasPendingLines() { return pendingLines || buffer.size() > 0; } } public class Producer implements Runnable { private FileMock mock; private Buffer buffer; public Producer(FileMock mock, Buffer buffer) { this.mock = mock; this.buffer = buffer; } @Override public void run() { buffer.setPendingLines(true); while(mock.hasMoreLines()) { String line = mock.getLine(); buffer.insert(line); } buffer.setPendingLines(false); } } public class Consumer implements Runnable { private Buffer buffer; public Consumer(Buffer buffer) { this.buffer = buffer; } @Override public void run() { while(buffer.hasPendingLines()) { String line = buffer.get(); processLine(line); } } private void processLine(String line) { try { Random random = new Random(); Thread.sleep(random.nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String[] args) { FileMock mock = new FileMock(100, 10); Buffer buffer = new Buffer(20); Producer producer = new Producer(mock, buffer); Thread threadProducer = new Thread(producer, "Producer"); Consumer consumer[] = new Consumer[3]; Thread threadConsumers[] = new Thread[3]; for(int i=0; i<3; i++) { consumer[i] = new Consumer(buffer); threadConsumers[i] = new Thread(consumer[i], "Consumer" + i); } threadProducer.start(); for(int i=3; i<3; i++) { threadConsumers[i].start(); } } }
三、线程同步辅助类
1、资源的并发访问控制
信号量(Semaphore)是一种计数器,用来保护一个或者多个共享资源的访问
Semaphore类还有其他两种acquire方法
acquireUninterruptibly()方法线程的中断不会抛出任何异常
tryAcquire()如果能获得信号量就返回true,不能就返回false
public class PrintQueue { private final Semaphore semaphore; public PrintQueue() { semaphore = new Semaphore(1); } public void printJob(Object document) { try { semaphore.acquire(); long duration = (long) (Math.random() * 10); System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n", Thread.currentThread().getName(), duration); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } } public class Job implements Runnable { private PrintQueue printQueue; public Job(PrintQueue printQueue) { this.printQueue = printQueue; } @Override public void run() { System.out.printf("%s Going to print a job\n", Thread.currentThread().getName()); printQueue.printJob(new Object()); System.out.printf("%s: The document has been printed\n", Thread.currentThread().getName()); } } public class Main { public static void main(String args[]) { PrintQueue printQueue = new PrintQueue(); Thread thread[] = new Thread[10]; for(int i=0; i<10; i++) { thread[i] = new Thread(new Job(printQueue), "Thread" + i); } for(int i=0; i<10; i++) { thread[i].start(); } } }
2、资源的多副本的并发访问控制
public class PrintQueue { private final Semaphore semaphore; private boolean freePrinters[]; private Lock lockPrinters; public PrintQueue() { semaphore = new Semaphore(3); freePrinters = new boolean[3]; for(int i=0; i<3; i++) { freePrinters[i] = true; } lockPrinters = new ReentrantLock(); } public void printJob(Object document) { try { semaphore.acquire(); int assignedPrinter = getPrinter(); long duration = (long) (Math.random() * 10); System.out.printf("%s: PrintQueue: Printing a Job in Printer %d during %d seconds\n", Thread.currentThread().getName(), assignedPrinter, duration); Thread.sleep(duration); freePrinters[assignedPrinter] = true; } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } private int getPrinter() { int ret = -1; try { lockPrinters.lock(); for(int i=0; i<freePrinters.length; i++) { if(freePrinters[i]) { ret = i; freePrinters[i] = false; break; } } } catch (Exception e) { e.printStackTrace(); } finally { lockPrinters.unlock(); } return ret; } } public class Job implements Runnable { private PrintQueue printQueue; public Job(PrintQueue printQueue) { this.printQueue = printQueue; } @Override public void run() { System.out.printf("%s Going to print a job\n", Thread.currentThread().getName()); printQueue.printJob(new Object()); System.out.printf("%s: The document has been printed\n", Thread.currentThread().getName()); } } public class Main { public static void main(String args[]) { PrintQueue printQueue = new PrintQueue(); Thread thread[] = new Thread[10]; for(int i=0; i<10; i++) { thread[i] = new Thread(new Job(printQueue), "Thread" + i); } for(int i=0; i<10; i++) { thread[i].start(); } } }
3、等待多个并发事件的完成
CountDownLatch类是一个同步辅助类,在完成一组正在替他线程中执行的操作之前,它允许线程一直等待
public class Videoconference implements Runnable { private final CountDownLatch controller; public Videoconference(int number) { controller = new CountDownLatch(number); } public void arrive(String name) { System.out.printf("%s has arrived.", name); controller.countDown(); System.out.printf("VideoConference: Waiting for %d participants.\n", controller.getCount()); } @Override public void run() { System.out.printf("VideoConference: Initialization: %d participants.\n", controller.getCount()); try { controller.await(); System.out.printf("VideoConference: All the participants have come\n"); System.out.printf("VideoCOnference: Let's start...\n"); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Participant implements Runnable { private Videoconference conference; private String name; public Participant(Videoconference conference, String name) { this.conference = conference; this.name = name; } @Override public void run() { long duration = (long) (Math.random() * 10); try { TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } conference.arrive(name); } } public class Main { public static void main(String[] args) { Videoconference conference = new Videoconference(10); Thread ThreadConference = new Thread(conference); ThreadConference.start(); for(int i=0; i<10; i++) { Participant p = new Participant(conference, "Participant " + i); Thread t = new Thread(p); t.start(); } } }
4、在集合点的同步
CyclicBarrier类也是一个同步辅助类,它允许两个或者多个线程在某个点上进行同步
它可以传入另一个Runnable对象作为初始化参数,当所有线程都到达集合点后,CyclicBarrier类将这个Runnable对象作为线程执行
public class MatrixMock { private int data[][]; public MatrixMock(int size, int length, int number) { int counter = 0; data = new int[size][length]; Random random = new Random(); for(int i=0; i<size; i++) { for(int j=0; j<length; j++) { data[i][j] = random.nextInt(10); if(data[i][j] == number) { counter++; } } } System.out.printf("Mock: There are %d ocurrences of number in generated data.\n", counter, number); } public int[] getRow(int row) { if((row>=0) && (row<data.length)) { return data[row]; } return null; } } public class Results { private int data[]; public Results(int size) { data = new int[size]; } public void setData(int position, int value) { data[position] = value; } public int[] getData() { return data; } } public class Searcher implements Runnable { private int firstRow; private int lastRow; private MatrixMock mock; private Results results; private int number; private final CyclicBarrier barrier; public Searcher(int firstRow, int lastRow, MatrixMock mock, Results results, int number, CyclicBarrier barrier) { this.firstRow = firstRow; this.lastRow = lastRow; this.mock = mock; this.results = results; this.number = number; this.barrier = barrier; } @Override public void run() { int counter; System.out.printf("%s Processing lines from %d to %d.\n", Thread.currentThread().getName(), firstRow, lastRow); for(int i=firstRow; i<lastRow; i++) { int row[] = mock.getRow(i); counter = 0; for(int j=0; j<row.length; j++) { if(row[j] == number) { counter++; } } results.setData(i, counter); } System.out.printf("%s: LineNumberInputStream processed.\n", Thread.currentThread().getName()); try { barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } public class Grouper implements Runnable { private Results results; public Grouper(Results results) { this.results = results; } @Override public void run() { int finalResult = 0; System.out.printf("Grouper: Processing results...\n"); int data[] = results.getData(); for(int number : data) { finalResult += number; } System.out.printf("Grouper: Total result: %d.\n", finalResult); } } public class Main { public static void main(String[] args) { final int ROWS = 10000; final int NUMBERS = 1000; final int SEARCH = 5; final int PARTICIPANTS = 5; final int LINES_PARTICIPANT = 2000; MatrixMock mock = new MatrixMock(ROWS, NUMBERS, SEARCH); Results results = new Results(ROWS); Grouper grouper = new Grouper(results); CyclicBarrier barrier = new CyclicBarrier(PARTICIPANTS, grouper); Searcher searchers[] = new Searcher[PARTICIPANTS]; for(int i=0; i<PARTICIPANTS; i++) { searchers[i] = new Searcher(i*LINES_PARTICIPANT, (i*LINES_PARTICIPANT) + LINES_PARTICIPANT, mock, results, 5, barrier); Thread thread = new Thread(searchers[i]); thread.start(); } System.out.printf("Main: The main thread has finished.\n"); } }
5、并发阶段任务的运行
Java并发API提供了一个更复杂、更强大的同步辅助类Phaser,它允许执行并发多阶段任务
public class FileSearch implements Runnable { private String initPath; private String end; private List<String> results; private Phaser phaser; public FileSearch(String initPath, String end, Phaser phaser) { this.initPath = initPath; this.end = end; this.phaser = phaser; results = new ArrayList<>(); } private void directoryProcess(File file) { File list[] = file.listFiles(); if(list != null) { for(int i=0; i<list.length; i++) { if(list[i].isDirectory()) { directoryProcess(list[i]); } else { fileProcess(list[i]); } } } } private void fileProcess(File file) { if(file.getName().endsWith(end)) { results.add(file.getAbsolutePath()); } } private void filterResults() { List<String> newResults = new ArrayList<>(); long actualDate = new Date().getTime(); for(int i =0; i<results.size(); i++) { File file = new File(results.get(i)); long fileDate = file.lastModified(); if(actualDate - fileDate < TimeUnit.MICROSECONDS.convert(1, TimeUnit.DAYS)) { newResults.add(results.get(i)); } } results = newResults; } private boolean checkResults() { if(results.isEmpty()) { System.out.printf("%s: Phase %d: 0 results.\n", Thread.currentThread().getName(), phaser.getPhase()); System.out.printf("%s: Phase %d: End.\n", Thread.currentThread().getName(), phaser.getPhase()); phaser.arriveAndDeregister(); return false; } else { System.out.printf("%s: Phase %d: %d results.\n", Thread.currentThread().getName(), phaser.getPhase(), results.size()); phaser.arriveAndAwaitAdvance(); return true; } } private void showInfo() { for(int i=0; i<results.size(); i++) { File file = new File(results.get(i)); System.out.printf("%s: %s\n", Thread.currentThread().getName(), file.getAbsolutePath()); } phaser.arriveAndAwaitAdvance(); } @Override public void run() { phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Starting.\n", Thread.currentThread().getName()); File file = new File(initPath); if(file.isDirectory()) { directoryProcess(file); } if(!checkResults()) { return; } filterResults(); if(!checkResults()) { return; } showInfo(); phaser.arriveAndDeregister(); System.out.printf("%s: Work completed.\n", Thread.currentThread().getName()); } } public class Main { public static void main(String[] args) { Phaser phaser = new Phaser(3); FileSearch system = new FileSearch("C:\\Windows", "log", phaser); FileSearch apps = new FileSearch("C:\\Program Files", "log", phaser); FileSearch documents = new FileSearch("C:\\SY", "log", phaser); Thread systemThread = new Thread(system, "System"); systemThread.start(); Thread appsThread = new Thread(apps, "Apps"); appsThread.start(); Thread documentsThread = new Thread(documents, "Documents"); documentsThread.start(); try { systemThread.join(); appsThread.join(); documentsThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Terminated: " + phaser.isTerminated()); } }
6、并发阶段任务中的阶段切换
public class MyPhaser extends Phaser { @Override protected boolean onAdvance(int phase, int registeredParties) { switch (phase) { case 0: return studentsArrived(); case 1: return finishFirstExercise(); case 2: return finishSecondExercise(); case 3: return finishExam(); default: return true; } } private boolean studentsArrived() { System.out.printf("Phaser: The exam are going to start. The students are ready.\n"); System.out.printf("Phaser: We have %d students.\n", getRegisteredParties()); return false; } private boolean finishFirstExercise() { System.out.printf("Phaser: All The students have finished the first exercise.\n"); System.out.printf("Phaser: It's time for the second one.\n"); return false; } private boolean finishSecondExercise() { System.out.printf("Phaser: All the students have finished the second exercise.\n"); System.out.printf("Phaser: It's time for the third one.\n"); return false; } private boolean finishExam() { System.out.printf("Phaser: All the students have finished the exam.\n"); System.out.printf("Phaser: Thank you for your time.\n"); return true; } } public class Student implements Runnable { private Phaser phaser; public Student(Phaser phaser) { this.phaser = phaser; } @Override public void run() { System.out.printf("%s: Has arrived to do the exam. %s\n", Thread.currentThread().getName(), new Date()); phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Is going to do the first exercise. %s\n", Thread.currentThread().getName(), new Date()); doExercise1(); System.out.printf("%s: Has done the first exercise. %s\n", Thread.currentThread().getName(), new Date()); phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Is going to do the Second exercise. %s\n", Thread.currentThread().getName(), new Date()); doExercise2(); System.out.printf("%s: Has done the Second exercise. %s\n", Thread.currentThread().getName(), new Date()); phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Is going to do the third exercise. %s\n", Thread.currentThread().getName(), new Date()); doExercise3(); System.out.printf("%s: Has done the first third. %s\n", Thread.currentThread().getName(), new Date()); phaser.arriveAndAwaitAdvance(); } private void doExercise1() { try { long duration = (long) (Math.random()*10); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } private void doExercise2() { try { long duration = (long) (Math.random()*10); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } private void doExercise3() { try { long duration = (long) (Math.random()*10); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String args[]) { MyPhaser phaser = new MyPhaser(); Student student[] = new Student[5]; for(int i=0; i<student.length; i++) { student[i] = new Student(phaser); phaser.register(); } Thread threads[] = new Thread[student.length]; for(int i=0; i<student.length; i++) { threads[i] = new Thread(student[i], "Student" + i); threads[i].start(); } for(int i=0; i<student.length; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Main: The phaser has finished: %s.\n", phaser.isTerminated()); } }
7、并发任务间的数据交换
同步辅助类Exchanger允许在并发任务之间交换数据,它允许在两个线程之间定义同步点(SynchronizationPoint),当两个线程都达到同步点时,他们交换数据结构
public class Producer implements Runnable { private List<String> buffer; private final Exchanger<List<String>> exchanger; public Producer(List<String> buffer, Exchanger<List<String>> exchanger) { this.buffer = buffer; this.exchanger = exchanger; } @Override public void run() { int cycle = 1; for(int i=0; i<10; i++) { System.out.printf("Producer: Cycle %d\n", cycle); for(int j=0; j<10; j++) { String message = "Event " + ((i*10) + j); System.out.printf("Producer: %s\n", message); buffer.add(message); } try { buffer = exchanger.exchange(buffer); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Producer: " + buffer.size()); cycle++; } } } public class Consumer implements Runnable { private List<String > buffer; private final Exchanger<List<String>> exchanger; public Consumer(List<String> buffer, Exchanger<List<String>> exchanger) { this.buffer = buffer; this.exchanger = exchanger; } @Override public void run() { int cycle = 1; for(int i=0; i<10; i++) { System.out.printf("Consumer: Cycle %d\n", cycle); try { buffer = exchanger.exchange(buffer); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Consumer: " + buffer.size()); for(int j=0; j<10; j++) { String message = buffer.get(0); System.out.println("Consumer: " + message); buffer.remove(0); } cycle++; } } } public class Main { public static void main(String[] args) { List<String> buffer1 = new ArrayList<>(); List<String> buffer2 = new ArrayList<>(); Exchanger<List<String>> exchanger = new Exchanger<>(); Producer producer = new Producer(buffer1, exchanger); Consumer consumer = new Consumer(buffer2, exchanger); Thread threadProducer = new Thread(producer); Thread threadConsumer = new Thread(consumer); threadProducer.start(); threadConsumer.start(); } }
四、线程执行器
1、创建线程执行器
ThreadPoolExecutor执行器
用Executors工厂类的newCachedThreadPool()方法创建缓存线程池,返回一个ExecutorService对象,同时被强制转换成ThreadPoolExecutor类型
仅当线程的数量是合理的或者线程只会运行很短的时间时,适合采用Executors工厂类的newCachedThreadPool()方法来创建执行器
使用execute()方法来发送Runnable或Callable类型的任务
使用shutdown()方法结束已经完成所有待运行任务的执行器
使用shutdownNow()方法结束,不再执行那些正在等待执行的任务
public class Task implements Runnable { private Date initDate; private String name; public Task(String name) { initDate = new Date(); this.name = name; } @Override public void run() { System.out.printf("%s: Task %s: Created on: %s\n", Thread.currentThread().getName(), name, initDate); System.out.printf("%s Task %s: Started on: %s\n", Thread.currentThread().getName(), name, initDate); try { Long duration = (long) (Math.random() * 10); System.out.printf("%s: Task %s: Doing a task during %d seconds\n", Thread.currentThread().getName(), name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Task %s: Finished on %s\n", Thread.currentThread().getName(), name, new Date()); } } public class Server { private ThreadPoolExecutor executor; public Server() { executor = (ThreadPoolExecutor)Executors.newCachedThreadPool(); } public void executeTask(Task task) { System.out.printf("Server: A new task has arrived\n"); executor.execute(task); System.out.printf("Server: Pool Size: %d\n", executor.getPoolSize()); System.out.printf("Server: Active Count: %d\n", executor.getActiveCount()); System.out.printf("Server: Completed Tasks: %d\n", executor.getCompletedTaskCount()); } public void endServer() { executor.shutdown(); } } public class Main { public static void main(String[] args) { Server server = new Server(); for(int i=0; i<100; i++) { Task task = new Task("Task " + i); server.executeTask(task); } server.endServer(); } }
2、创建固定大小的线程执行器
使用newFixedThreadPool()方法创建固定大小的线程执行器
public class Server { private ThreadPoolExecutor executor; public Server() { executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(5); } public void executeTask(Task task) { System.out.printf("Server: A new task has arrived\n"); executor.execute(task); System.out.printf("Server: Pool Size: %d\n", executor.getPoolSize()); System.out.printf("Server: Active Count: %d\n", executor.getActiveCount()); System.out.printf("Server: Completed Tasks: %d\n", executor.getCompletedTaskCount()); System.out.printf("Server: Task Count: %d\n", executor.getTaskCount()); } public void endServer() { executor.shutdown(); } } public class Task implements Runnable { private Date initDate; private String name; public Task(String name) { initDate = new Date(); this.name = name; } @Override public void run() { System.out.printf("%s: Task %s: Created on: %s\n", Thread.currentThread().getName(), name, initDate); System.out.printf("%s Task %s: Started on: %s\n", Thread.currentThread().getName(), name, initDate); try { Long duration = (long) (Math.random() * 10); System.out.printf("%s: Task %s: Doing a task during %d seconds\n", Thread.currentThread().getName(), name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Task %s: Finished on %s\n", Thread.currentThread().getName(), name, new Date()); } } public class Main { public static void main(String[] args) { Server server = new Server(); for(int i=0; i<100; i++) { Task task = new Task("Task " + i); server.executeTask(task); } server.endServer(); } }
3、在执行器中执行任务并返回结果
Callable接口声明了call方法用来返回结果,future获取由Callable对象产生的结果并管理它们的状态
在调用future对象的get()方法时,如果future对象所控制的任务并未完成,那么这个方法将一直阻塞到任务完成
public class FactorialCalculator implements Callable<Integer>{ private Integer number; public FactorialCalculator(Integer number) { this.number = number; } @Override public Integer call() throws Exception { int result = 1; if((number == 0) || number == 1) { result = 1; } else { for(int i=2; i<number; i++) { result *= i; TimeUnit.MILLISECONDS.sleep(20); } } System.out.printf("%s: %d\n", Thread.currentThread().getName(), result); return result; } } public class Main { public static void main(String[] args) { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); List<Future<Integer>> resultList = new ArrayList<>(); Random random = new Random(); for(int i=0; i<10; i++) { Integer number = random.nextInt(10); FactorialCalculator calculator = new FactorialCalculator(number); Future<Integer> result = executor.submit(calculator); resultList.add(result); } do { System.out.printf("Main: Number of Completed Tasks: %d\n", executor.getCompletedTaskCount()); for(int i=0; i<resultList.size(); i++) { Future<Integer> result = resultList.get(i); System.out.printf("Main: Task %d: %s\n", i, result.isDone()); } try { TimeUnit.MICROSECONDS.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } while (executor.getCompletedTaskCount() < resultList.size()); System.out.printf("Main: Results\n"); for(int i=0; i<resultList.size(); i++) { Future<Integer> result = resultList.get(i); Integer number = null; try { number = result.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.printf("Main: Task %d: %d\n", i, number); } executor.shutdown(); } }
5、运行多个任务并处理第一个结果
使用ThreadPoolExecutor类的invokeAny方法接收一个任务列表,返回第一个完成任务并且没有抛出异常的任务的执行结果,这个方法返回的类型与任务里call()方法返回的类型相同
public class UserValidator { private String name; public UserValidator(String name) { this.name = name; } public boolean validate(String name, String password) { Random randon = new Random(); try { long duration = (long) (Math.random() * 10); System.out.printf("Validator %s: Validating a user during %d seconds\n", this.name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { return false; } return randon.nextBoolean(); } public String getName() { return name; } } public class TaskValidator implements Callable<String> { private UserValidator validator; private String user; private String password; public TaskValidator(UserValidator validator, String user, String password) { this.validator = validator; this.user = user; this.password = password; } @Override public String call() throws Exception { if(!validator.validate(user, password)) { System.out.printf("%s: The user has not been found\n", validator.getName()); throw new Exception("Errer validating user"); } System.out.printf("%s: The user has been found\n", validator.getName()); return validator.getName(); } } public class Main { public static void main(String[] args) { String username = "test"; String password = "test"; UserValidator ldapValidator = new UserValidator("LDAP"); UserValidator dbValidator = new UserValidator("DataBase"); TaskValidator ldapTask = new TaskValidator(ldapValidator, username, password); TaskValidator dbTask = new TaskValidator(dbValidator, username, password); List<TaskValidator> taskList = new ArrayList<>(); taskList.add(ldapTask); taskList.add(dbTask); ExecutorService executor = (ExecutorService) Executors.newCachedThreadPool(); String result; try { result = executor.invokeAny(taskList); System.out.printf("Main: Result: %s\n", result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } executor.shutdown(); System.out.printf("Main: End of the Execution\n"); } }
5、运行多个任务并处理所有结果
使用ThreadPoolExecutor类的invokeAll方法接收一个任务列表,等待所有任务的完成
public class Result { private String name; private int value; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } } public class Task implements Callable<Result> { private String name; public Task(String name) { this.name = name; } @Override public Result call() throws Exception { System.out.printf("%s: Starting\n", this.name); try { long duration = (long) (Math.random() * 10); System.out.printf("%s: Waiting %d seconds for results.\n", this.name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } int value = 0; for(int i=0; i<5; i++) { value += (int) (Math.random() * 100); } Result result = new Result(); result.setName(this.name); result.setValue(value); System.out.println(this.name + ": Ends"); return result; } } public class Main { public static void main(String[] args) { ExecutorService executor = (ExecutorService) Executors.newCachedThreadPool(); List<Task> taskList = new ArrayList<>(); for(int i=0; i<3; i++) { Task task = new Task(String.valueOf(i)); taskList.add(task); } List<Future<Result>> resultList = null; try { resultList = executor.invokeAll(taskList); } catch (InterruptedException e) { e.printStackTrace(); } executor.shutdown(); System.out.println("Main: Printing the results"); for(int i=0; i<resultList.size(); i++) { Future<Result> future = resultList.get(i); try { Result result = future.get(); System.out.println(result.getName() + ": " + result.getValue()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } }
6、在执行器中延时执行任务
使用ScheduledThreadPoolExecutor执行器的schedule()方法设置一段时间后执行一个任务
ScheduledThreadPoolExecutor执行器使用newScheduledThreadPool()方法创建
调用awaitTermination()方法等待所有任务结束
public class Task implements Callable<String> { private String name; public Task(String name) { this.name = name; } @Override public String call() throws Exception { System.out.printf("%s: Strating at : %s\n", name, new Date()); return "Hello, world"; } } public class Main { public static void main(String[] args) { ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1); System.out.printf("Main: Starting at: %s\n", new Date()); for(int i=0; i<5; i++) { Task task = new Task("Task " + i); executor.schedule(task, i+1, TimeUnit.SECONDS); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Ends at: %s\n", new Date()); } }
7、在执行器中周期性执行任务
使用ScheduledExecutorService对象的scheduleAtFixedRate()方法执行周期性任务
scheduleAtFixedRate()方法的第2个参数为任务第一次执行后的延时时间,第3个参数为两次执行的时间周期
scheduleWithFixedDelay()方法略有不同,第3个参数为任务上一次执行结束时间与任务下一次开始执行的时间的间隔
ScheduleFuture接口的getDelay()方法返回任务到下一次执行时所要等待的剩余时间
public class Task implements Runnable { private String name; public Task(String name) { this.name = name; } @Override public void run() { System.out.printf("%s: Starting at : %s\n", name, new Date()); } } public class Main { public static void main(String[] args) { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); System.out.printf("Main: Starting at: %s\n", new Date()); Task task = new Task("Task"); ScheduledFuture<?> result = executor.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS); for(int i=0; i<20; i++) { System.out.printf("Main: Delay: %d\n", result.getDelay(TimeUnit.MILLISECONDS)); try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } executor.shutdown(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Finished at: %s\n", new Date()); } }
8、在执行器中取消任务
使用Future接口的cancel()方法取消一个已经发送给执行器的任务
如果传的参数为true,正在运行的任务会被取消,如果为false,只取消在执行器中等待分配Thread对象的任务
public class Task implements Callable<String> { @Override public String call() throws Exception { while(true) { System.out.printf("Task: Test\n"); Thread.sleep(100); } } } public class Main { public static void main(String[] args) { ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool(); Task task = new Task(); System.out.printf("Main: Executing the Task\n"); Future<String> result = executor.submit(task); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Canceling the Task\n"); result.cancel(true); System.out.printf("Main: Cancelled: %s\n", result.isCancelled()); System.out.printf("Main: Done: %s\n", result.isDone()); executor.shutdown(); System.out.printf("Main: The executor has finished\n"); } }
9、在执行器中控制任务的完成
FutureTask提供了done()方法,无论任务是被取消或者正常结束,done()方法都会被调用
继承FutureTask来重写done()方法,可以通过任务来关闭系统资源、输出日志信息、发送通知等
public class ExecutableTask implements Callable<String> { private String name; public String getName() { return name; } public ExecutableTask(String name) { this.name = name; } @Override public String call() throws Exception { try { long duration = (long) (Math.random() * 10); System.out.printf("%s: Waiting %d seconds for results.\n", this.name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { } return "Hello, world. I'm " + name; } } public class ResultTask extends FutureTask<String> { private String name; public ResultTask(Callable<String> callable) { super(callable); this.name = ((ExecutableTask)callable).getName(); } @Override protected void done() { if(isCancelled()) { System.out.printf("%s: Has been canceled\n", name); } else { System.out.printf("%s: Has finished\n", name); } } } public class Main { public static void main(String[] args) { ExecutorService executor = (ExecutorService)Executors.newCachedThreadPool(); ResultTask resultTasks[] = new ResultTask[5]; for(int i=0; i<5; i++) { ExecutableTask executableTask = new ExecutableTask("Task " + i); resultTasks[i] = new ResultTask(executableTask); executor.submit(resultTasks[i]); } try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } for(int i=0; i<resultTasks.length; i++) { resultTasks[i].cancel(true); } for(int i=0; i<resultTasks.length; i++) { try { if(!resultTasks[i].isCancelled()) { System.out.printf("%s\n", resultTasks[i].get()); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } executor.shutdown(); } }
10、在执行器中分离任务的启动与结果的处理
public class ReportGenerator implements Callable<String> { private String sender; private String title; public ReportGenerator(String sender, String title) { this.sender = sender; this.title = title; } @Override public String call() throws Exception { try { long duration = (long) (Math.random() * 10); System.out.printf("%s_%s: ReportGenerator: Generating a report During %d seconds\n", this.sender, this.title, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } String ret = sender + ": " + title; return ret; } } public class ReportRequest implements Runnable { private String name; private CompletionService<String> service; public ReportRequest(String name, CompletionService<String> service) { this.name = name; this.service = service; } @Override public void run() { ReportGenerator reportGenerator = new ReportGenerator(name, "Report"); service.submit(reportGenerator); } } public class ReportProcessor implements Runnable { private CompletionService<String> service; private boolean end; public ReportProcessor(CompletionService<String> service) { this.service = service; end = false; } @Override public void run() { while(!end) { try { Future<String> result = service.poll(20, TimeUnit.SECONDS); if(result != null) { String report = result.get(); System.out.printf("ReportReceiver: Report Received: %s\n", report); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } System.out.printf("ReportSender: End\n"); } public void setEnd(boolean end) { this.end = end; } } public class Main { public static void main(String[] args) { ExecutorService executor = (ExecutorService)Executors.newCachedThreadPool(); CompletionService<String> service = new ExecutorCompletionService<>(executor); ReportRequest faceRequest = new ReportRequest("Face", service); ReportRequest onlineRequest = new ReportRequest("Online", service); Thread faceThread = new Thread(faceRequest); Thread onlineThread = new Thread(onlineRequest); ReportProcessor processor = new ReportProcessor(service); Thread senderThread = new Thread(processor); System.out.printf("Main: Starting the Threads\n"); faceThread.start(); onlineThread.start(); senderThread.start(); try { System.out.printf("Main Waiting for the report generators.\n"); faceThread.join(); onlineThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Shutting down the executor.\n"); executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } processor.setEnd(true); System.out.println("Main: Ends"); } }
11、处理在执行器中被拒绝的任务
public class RejectedTaskController implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.printf("RejectedTaskController: The task %s has been rejected\n", r.toString()); System.out.printf("RejectedTaskController: %s\n", executor.toString()); System.out.printf("RejectedTaskController: Terminating: %s\n", executor.isTerminating()); System.out.printf("RejectedTaksController: Terminated: %s\n", executor.isTerminated()); } } public class Task implements Runnable { private String name; public Task(String name) { this.name = name; } @Override public void run() { System.out.printf("Task " + name + ": Starting"); try { long duration = (long) (Math.random() * 10); System.out.printf("Task %s: ReportGenerator: Generating a report during %d seconds\n", name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Task %s: Ending\n", name); } public String toString() { return name; } } public class Main { public static void main(String[] args) { RejectedTaskController controller = new RejectedTaskController(); ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool(); executor.setRejectedExecutionHandler(controller); System.out.printf("Main: Starting.\n"); for(int i=0; i<3; i++) { Task task = new Task("Task" + i); executor.submit(task); } System.out.printf("Main: Shutting down the Executor.\n"); executor.shutdown(); System.out.printf("Main: Sending another Task.\n"); Task task = new Task("RejectedTask"); executor.submit(task); System.out.printf("Main: End.\n"); } }
五、Fork/Join框架
1、创建Fork/Join线程
ForkJoinPool实现了ExecutorService接口和工作窃取算法
ForkJoinTask是一个将在ForkJoinPool中执行任务的基类
RecursiveAction用于任务没有返回结果的场景
RecursiveTask用于任务有返回结果的场景
public class Product { private String name; private double price; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } } public class ProductListGenerator { public List<Product> generate(int size) { List<Product> ret = new ArrayList<Product>(); for(int i=0; i<size; i++) { Product product = new Product(); product.setName("Product " + i); product.setPrice(10); ret.add(product); } return ret; } } public class Task extends RecursiveAction { private static final long serialVersionUID = 1L; private List<Product> products; private int first; private int last; private double increment; public Task(List<Product> products, int first, int last, double increment) { this.products = products; this.first = first; this.last = last; this.increment = increment; } @Override protected void compute() { if(last-first < 10) { updatePrices(); } else { int middle = (last+first)/2; System.out.printf("Task: Pending taskds: %s\n", getQueuedTaskCount()); Task t1 = new Task(products, first, middle+1, increment); Task t2 = new Task(products, middle+1, last, increment); invokeAll(t1, t2); } } private void updatePrices() { for(int i=first; i<last; i++) { Product product = products.get(i); product.setPrice(product.getPrice()*(i+increment)); } } } public class Main { public static void main(String[] args) { ProductListGenerator generator = new ProductListGenerator(); List<Product> products = generator.generate(10000); Task task = new Task(products, 0, products.size(), 0.20); ForkJoinPool pool = new ForkJoinPool(); pool.execute(task); do { System.out.printf("Main: Thread Count: %d\n", pool.getActiveThreadCount()); System.out.printf("Main: Thread Steal: %d\n", pool.getStealCount()); System.out.printf("Main: Parallelism: %d\n", pool.getParallelism()); try { TimeUnit.MILLISECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } while(!task.isDone()); pool.shutdown(); if(task.isCompletedNormally()) { System.out.printf("Main: The proess has completed normally.\n"); } for(int i=0; i<products.size(); i++) { Product product = products.get(1); System.out.println(product.getPrice()); if(product.getPrice() != 12) { System.out.printf("Main: End of the program.\n"); } } } }
2、合并任务的结果
public class DocumentMock { private String words[] = {"this", "hello", "goodbye", "packt", "java", "thread", "pool", "random", "class", "main"}; public String[][] generateDocument(int numLines, int numWords, String word) { int counter = 0; String document[][] = new String[numLines][numWords]; Random random = new Random(); for(int i=0; i<numLines; i++) { for(int j=0; j<numWords; j++) { int index = random.nextInt(words.length); document[i][j] = words[index]; if(document[i][j].equals(word)) { counter++; } } } System.out.println("DocumentMock: The word appears " + counter + " times in the document"); return document; } } public class DocumentTask extends RecursiveTask<Integer> { private String document[][]; private int start, end; private String word; public DocumentTask(String document[][], int start, int end, String word) { this.document = document; this.start = start; this.end = end; this.word = word; } @Override protected Integer compute() { int result = 0; if(end-start < 10) { result = processLines(document, start, end, word); } else { int mid = (start + end) / 2; DocumentTask task1 = new DocumentTask(document, start, mid, word); DocumentTask task2 = new DocumentTask(document, mid, end, word); invokeAll(task1, task2); try { result = groupResults(task1.get(), task2.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } return result; } private Integer processLines(String[][] document, int start, int end, String word) { List<LineTask> tasks = new ArrayList<LineTask>(); for(int i=start; i<end; i++) { LineTask task = new LineTask(document[i], 0, document[i].length, word); tasks.add(task); } invokeAll(tasks); int result = 0; for(int i=0; i<tasks.size(); i++) { LineTask task = tasks.get(i); try { result = result + task.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } return new Integer(result); } private Integer groupResults(Integer number1, Integer number2) { Integer result; result = number1 + number2; return result; } } public class LineTask extends RecursiveTask<Integer> { private static final long serialVersionUID = 1L; private String line[]; private int start, end; private String word; public LineTask(String line[], int start, int end, String word) { this.line = line; this.start = start; this.end = end; this.word = word; } @Override protected Integer compute() { Integer result = null; if(end-start < 100) { result = count(line, start, end, word); } else { int mid = (start + end) / 2; LineTask task1 = new LineTask(line, start, mid, word); LineTask task2 = new LineTask(line, mid, end, word); invokeAll(task1, task2); try { result = groupResults(task1.get(), task2.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } return result; } private Integer count(String[] line, int start, int end, String word) { int counter; counter = 0; for(int i=start; i<end; i++) { if(line[i].equals(word)) { counter++; } } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } return counter; } private Integer groupResults(Integer number1, Integer number2) { Integer result; result = number1 + number2; return result; } } public class Main { public static void main(String[] args) { DocumentMock mock = new DocumentMock(); String[][] document = mock.generateDocument(100, 1000, "the"); DocumentTask task = new DocumentTask(document, 0, 100, "the"); ForkJoinPool pool = new ForkJoinPool(); pool.execute(task); do { System.out.printf("*****************************\n"); System.out.printf("Main: Parallelism: %d\n", pool.getParallelism()); System.out.printf("Main: Active Threads: %d\n", pool.getActiveThreadCount()); System.out.printf("Main: Task Count: %d\n", pool.getQueuedTaskCount()); System.out.printf("Main: Steal Count: %d\n", pool.getStealCount()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } while(!task.isDone()); pool.shutdown(); try { pool.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } try { System.out.printf("Main: The word appears %d in the document", task.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
3、异步运行任务
public class FolderProcessor extends RecursiveTask<List<String>> { private String path; private String extension; public FolderProcessor(String path, String extension) { this.path = path; this.extension = extension; } @Override protected List<String> compute() { List<String> list = new ArrayList<>(); List<FolderProcessor> tasks = new ArrayList<>(); File file = new File(path); File content[] = file.listFiles(); if(content != null) { for(int i=0; i<content.length; i++) { if(content[i].isDirectory()) { FolderProcessor task = new FolderProcessor(content[i].getAbsolutePath(), extension); task.fork(); tasks.add(task); } else { if(checkFile(content[i].getName())) { list.add(content[i].getAbsolutePath()); } } } } if(tasks.size() > 50) { System.out.printf("%s: %d tasks ran.\n", file.getAbsolutePath(), tasks.size()); } addResultsFromTasks(list, tasks); return list; } private void addResultsFromTasks(List<String> list, List<FolderProcessor> tasks) { for(FolderProcessor item : tasks) { list.addAll(item.join()); } } private boolean checkFile(String name) { return name.endsWith(extension); } } public class Main { public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(); FolderProcessor system = new FolderProcessor("C:\\Windows", "log"); FolderProcessor apps = new FolderProcessor("C:\\Program Files", "log"); FolderProcessor documents = new FolderProcessor("C:\\Users", "log"); pool.execute(system); pool.execute(apps); pool.execute(documents); do { System.out.printf("**************************\n"); System.out.printf("Main: Parallelistm: %d\n", pool.getParallelism()); System.out.printf("Main: Active Threads: %d\n", pool.getActiveThreadCount()); System.out.printf("Main: Task Count: %d\n", pool.getQueuedTaskCount()); System.out.printf("Main: Steal Count: %d\n", pool.getStealCount()); System.out.printf("**************************\n"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } while((!system.isDone()) || (!apps.isDone()) || (!documents.isDone())); pool.shutdown(); List<String> results; results = system.join(); System.out.printf("System: %d files found.\n", results.size()); results = apps.join(); System.out.printf("Apps: %d files found.\n", results.size()); results = documents.join(); System.out.printf("Document: %d files found.\n", results.size()); } }
4、在任务中抛出异常
public class Task extends RecursiveTask<Integer> { private int array[]; private int start, end; public Task(int array[], int start, int end) { this.array = array; this.start = start; this.end = end; } @Override protected Integer compute() { System.out.printf("Task: Start from %d to %d\n", start, end); if(end-start < 10) { if((3>start)&&(3<end)) { throw new RuntimeException("This task throws an Exception: Task from " + start + " to " + end); } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } else { int mid = (end+start) /2; Task task1 = new Task(array, start, end); Task task2 = new Task(array, mid, end); invokeAll(task1, task2); } System.out.printf("Task: End form %d to %d\n", start, end); return 0; } } public class Main { public static void main(String[] args) { int array[] = new int[100]; Task task = new Task(array, 0, 100); ForkJoinPool pool = new ForkJoinPool(); pool.execute(task); pool.shutdown(); try { pool.awaitQuiescence(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } if(task.isCompletedAbnormally()) { System.out.printf("Main: An exception has ocurred\n"); System.out.printf("Main: %s\n", task.getException()); } System.out.printf("Main: Result: %d", task.join()); } }
5、取消任务
public class ArrayGenerator { public int[] generateArray(int size) { int array[] = new int[size]; Random random = new Random(); for(int i=0; i<size; i++) { array[i] = random.nextInt(10); } return array; } } public class TaskManager { private List<ForkJoinTask<Integer>> tasks; public TaskManager() { tasks = new ArrayList<>(); } public void addTask(ForkJoinTask<Integer> task) { tasks.add(task); } public void cancelTasks(ForkJoinTask<Integer> cancelTask) { for(ForkJoinTask<Integer> task : tasks) { if(task != cancelTask) { task.cancel(true); ((SearchNumberTask)task).writeCancelMessage(); } } } } public class SearchNumberTask extends RecursiveTask<Integer> { private int numbers[]; private int start, end; private int number; private TaskManager manager; private final static int NOT_FOUND = -1; public SearchNumberTask(int numbers[], int start, int end, int number, TaskManager manager) { this.numbers = numbers; this.start = start; this.end = end; this.number = number; this.manager = manager; } @Override protected Integer compute() { System.out.println("Task: " + start + ":" + end); int ret; if(end-start > 10) { ret = launchTasks(); } else { ret = lookForNumber(); } return ret; } private int lookForNumber() { for(int i=start; i<end; i++) { if(numbers[i] == number) { System.out.printf("Task: Number %d found in position %d\n", number, i); manager.cancelTasks(this); return i; } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } return NOT_FOUND; } private int launchTasks() { int mid = (start+end) / 2; SearchNumberTask task1 = new SearchNumberTask(numbers, start, mid, number, manager); SearchNumberTask task2 = new SearchNumberTask(numbers, mid, end, number, manager); manager.addTask(task1); manager.addTask(task2); task1.fork(); task2.fork(); int returnValue; returnValue = task1.join(); if(returnValue != -1) { return returnValue; } returnValue = task2.join(); return returnValue; } public void writeCancelMessage() { System.out.printf("Task: Cancelled task from %d to %d\n", start, end); } } public class Main { public static void main(String[] args) { ArrayGenerator generator = new ArrayGenerator(); int array[] = generator.generateArray(1000); TaskManager manager = new TaskManager(); ForkJoinPool pool = new ForkJoinPool(); SearchNumberTask task = new SearchNumberTask(array, 0, 1000, 5, manager); pool.execute(task); pool.shutdown(); try { pool.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: The program has finished\n"); } }
六、并发集合
Java提供了两类适用于并发应用的集合:
阻塞式集合(Blocking Collection)当集合已满或为空时,添加或者移除的方法就不能立即被执行,一直阻塞到该方法可以被成功执行
非阻塞式集合(Non-Blocking Collection)这类集合如果不能立即被执行,则返回null或抛出异常,调用这个方法的线程不会被阻塞
1、使用非阻塞式线程安全列表
非阻塞式列表对应的实现类:ConcurrentLinkedDeque
public class AddTask implements Runnable { private ConcurrentLinkedDeque<String> list; public AddTask(ConcurrentLinkedDeque<String> list) { this.list = list; } @Override public void run() { String name = Thread.currentThread().getName(); for(int i=0; i<10000; i++) { list.add(name + ": Element " + i); } } } public class PollTask implements Runnable { private ConcurrentLinkedDeque<String> list; public PollTask(ConcurrentLinkedDeque<String> list) { this.list = list; } @Override public void run() { for(int i=0; i<5000; i++) { list.pollFirst(); list.pollLast(); } } } public class Main { public static void main(String[] args) { ConcurrentLinkedDeque<String> list = new ConcurrentLinkedDeque<>(); Thread threads[] = new Thread[100]; for(int i=0; i<threads.length; i++) { AddTask task = new AddTask(list); threads[i] = new Thread(task); threads[i].start(); } System.out.printf("Main: %d AddTask threads have been launched\n", threads.length); for(int i=0; i<threads.length; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Main: Size of the List: %d\n", list.size()); for(int i=0; i<threads.length; i++) { PollTask task = new PollTask(list); threads[i] = new Thread(task); threads[i].start(); } System.out.printf("Main: %d PollTask Thread have been launched\n", threads.length); for(int i=0; i<threads.length; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Main: Size of the List: %d\n", list.size()); } }
2、使用阻塞式线程安全列表
阻塞式列表对应的实现类:LinkedBlockingDeque
public class Client implements Runnable { private LinkedBlockingDeque<String> requestList; public Client(LinkedBlockingDeque<String> requestList) { this.requestList = requestList; } @Override public void run() { for(int i=0; i<3; i++) { for(int j=0; j<5; j++) { StringBuilder request = new StringBuilder(); request.append(i); request.append(":"); request.append(j); try { requestList.put(request.toString()); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Client: %s at %s.\n", request, new Date()); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Client: End.\n"); } } public class Main { public static void main(String[] args) throws Exception { LinkedBlockingDeque<String> list = new LinkedBlockingDeque<>(3); Client client = new Client(list); Thread thread = new Thread(client); thread.start(); for(int i=0; i<5; i++) { for(int j=0; j<3; j++) { String request = list.take(); System.out.printf("Main: Request: %s at %s. Size: %d\n", request, new Date(), list.size()); } } System.out.printf("Main: End of the program.\n"); } }
3、使用按优先级排序的阻塞式线程安全列表
按优先级排序列表元素的阻塞式列表:PriorityBlockingQueue
public class Event implements Comparable<Event> { private int thread; private int priority; public Event(int thread, int priority) { this.thread = thread; this.priority = priority; } public int getThread() { return thread; } public int getPriority() { return priority; } @Override public int compareTo(Event e) { if(this.priority > e.getPriority()) { return -1; } else if(this.priority < e.getPriority()) { return 1; } else { return 0; } } } public class Task implements Runnable { private int id; private PriorityBlockingQueue<Event> queue; public Task(int id, PriorityBlockingQueue<Event> queue) { this.id = id; this.queue = queue; } @Override public void run() { for(int i=0; i<1000; i++) { Event event = new Event(id, i); queue.add(event); } } } public class Main { public static void main(String[] args) { PriorityBlockingQueue<Event> queue = new PriorityBlockingQueue<>(); Thread taskThreads[] = new Thread[5]; for(int i=0; i<taskThreads.length; i++) { Task task = new Task(i, queue); taskThreads[i] = new Thread(task); } for(int i=0; i<taskThreads.length; i++) { taskThreads[i].start(); } for(int i=0; i<taskThreads.length; i++) { try { taskThreads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Main: Queue Size: %d\n", queue.size()); for(int i=0; i<taskThreads.length*1000; i++) { Event event = queue.poll(); System.out.printf("Thread %s: Priority %d\n", event.getThread(), event.getPriority()); } System.out.printf("Main: Queue Size: %d\n", queue.size()); System.out.printf("Main: End of the program\n"); } }
4、使用带有延迟元素的线程安全列表
带有延迟列表元素的阻塞式列表:DelayQueue
public class Event implements Delayed { private Date startDate; public Event(Date startDate) { this.startDate = startDate; } @Override public int compareTo(Delayed o) { long result = this.getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS); if(result < 0) { return -1; } else if(result > 0) { return 1; } return 0; } public long getDelay(TimeUnit unit) { Date now = new Date(); long diff = startDate.getTime() - now.getTime(); return unit.convert(diff, TimeUnit.MILLISECONDS); } } public class Task implements Runnable { private int id; private DelayQueue<Event> queue; public Task(int id, DelayQueue<Event> queue) { this.id = id; this.queue = queue; } @Override public void run() { Date now = new Date(); Date delay = new Date(); delay.setTime(now.getTime() + (id*1000)); System.out.printf("Thread %s: %s\n", id, delay); for(int i=0; i<100; i++) { Event event = new Event(delay); queue.add(event); } } } public class Main { public static void main(String[] args) throws InterruptedException { DelayQueue<Event> queue = new DelayQueue<>(); Thread threads[] = new Thread[5]; for(int i=0; i<threads.length; i++) { Task task = new Task(i+1, queue); threads[i] = new Thread(task); } for(int i=0; i<threads.length; i++) { threads[i].start(); } for(int i=0; i<threads.length; i++) { threads[i].join(); } do { int counter = 0; Event event; do { event = queue.poll(); if(event != null) counter++; } while(event != null); System.out.printf("At %s you have read %d events\n", new Date(), counter); TimeUnit.MILLISECONDS.sleep(500); } while(queue.size() > 0); } }
5、使用线程安全可遍历映射
非阻塞式可比案例映射ConcurrentSkipListMap
public class Contact { private String name; private String phone; public Contact(String name, String phone) { this.name = name; this.phone = phone; } public String getName() { return name; } public String getPhone() { return phone; } } public class Task implements Runnable { private ConcurrentSkipListMap<String, Contact> map; private String id; public Task(ConcurrentSkipListMap<String, Contact> map, String id) { this.id = id; this.map = map; } @Override public void run() { for(int i=0; i<1000; i++) { Contact contact = new Contact(id, String.valueOf(i+1000)); map.put(id+contact.getPhone(), contact); } } } public class Main { public static void main(String[] args) { ConcurrentSkipListMap<String, Contact> map = new ConcurrentSkipListMap<>(); Thread threads[] = new Thread[25]; int counter = 0; for(char i='A'; i<'Z'; i++) { Task task = new Task(map, String.valueOf(i)); threads[counter] = new Thread(task); threads[counter].start(); counter++; } for(int i=0; i<25; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Main: Size of the map %d\n", map.size()); Map.Entry<String, Contact> element; Contact contact; element = map.firstEntry(); contact = element.getValue(); System.out.printf("Main: First Entry: %s: %s\n", contact.getName(), contact.getPhone()); element = map.lastEntry(); contact = element.getValue(); System.out.printf("Main: Last Entry: %s: %s\n", contact.getName(), contact.getPhone()); System.out.printf("Main: Submap from A1996 to B1002: \n"); ConcurrentNavigableMap<String, Contact> submap = map.subMap("A1996", "B1002"); do { element = submap.pollFirstEntry(); if(element != null) { contact = element.getValue(); System.out.printf("%s: %s\n", contact.getName(), contact.getPhone()); } } while (element != null); } }
6、生成并发随机数
在并发应用中高效生成随机数:ThreadLocalRandom
public class TaskLocalRandom implements Runnable { public TaskLocalRandom() { ThreadLocalRandom.current(); } @Override public void run() { String name = Thread.currentThread().getName(); for(int i=0; i<10; i++) { System.out.printf("%s: %d\n", name, ThreadLocalRandom.current().nextInt(10)); } } } public class Main { public static void main(String[] args) { Thread threads[] = new Thread[3]; for(int i=0; i<3; i++) { TaskLocalRandom task = new TaskLocalRandom(); threads[i] = new Thread(task); threads[i].start(); } } }
7、使用原子变量
原子变量不使用锁或其他同步机制来保护对其值的并发访问。所有操作都是基于CAS原子操作的。它保证了多线程在同一时间操作一个原子变量而不会产生数据不一致的错误,并且它的性能优于使用同步机制保护的普通变量
public class Account { private AtomicLong balance; public Account() { balance = new AtomicLong(); } public long getBalanec() { return balance.get(); } public void setBalance(long balance) { this.balance.set(balance); } public void addAmount(long amount) { this.balance.getAndAdd(amount); } public void subtractAmount(long amount) { this.balance.getAndAdd(-amount); } } public class Company implements Runnable { private Account account; public Company(Account account) { this.account = account; } @Override public void run() { for(int i=0; i<10; i++) { account.addAmount(1000); } } } public class Bank implements Runnable { private Account account; public Bank(Account account) { this.account = account; } @Override public void run() { for(int i=0; i<10; i++) { account.subtractAmount(1000); } } } public class Main { public static void main(String[] args) { Account account = new Account(); account.setBalance(1000); Company company = new Company(account); Thread companyThread = new Thread(company); Bank bank = new Bank(account); Thread bankThread = new Thread(bank); System.out.printf("Account: Initial Balance: %d\n", account.getBalanec()); companyThread.start(); bankThread.start(); try { companyThread.join(); bankThread.join(); System.out.printf("Account: Final Balance: %d\n", account.getBalanec()); } catch (InterruptedException e) { e.printStackTrace(); } } }
8、使用原子数组
public class Incrementer implements Runnable { private AtomicIntegerArray vector; public Incrementer(AtomicIntegerArray vector) { this.vector = vector; } @Override public void run() { for(int i=0; i<vector.length(); i++) { vector.getAndIncrement(i); } } } public class Decrementer implements Runnable { private AtomicIntegerArray vector; public Decrementer(AtomicIntegerArray vector) { this.vector = vector; } @Override public void run() { for(int i=0; i<vector.length(); i++) { vector.getAndDecrement(i); } } } public class Main { public static void main(String[] args) { final int THREADS = 100; AtomicIntegerArray vector = new AtomicIntegerArray(1000); Incrementer incrementer = new Incrementer(vector); Decrementer decrementer = new Decrementer(vector); Thread threadIncrementer[] = new Thread[THREADS]; Thread threadDecrementer[] = new Thread[THREADS]; for(int i=0; i<THREADS; i++) { threadIncrementer[i] = new Thread(incrementer); threadDecrementer[i] = new Thread(decrementer); threadIncrementer[i].start(); threadDecrementer[i].start(); } for(int i=0; i<100; i++) { try { threadIncrementer[i].join(); threadDecrementer[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0; i<vector.length(); i++) { if(vector.get(i) != 0) { System.out.println("Vector[" + i + "]: " + vector.get(i)); } } System.out.println("Main: End of the example"); } }
七、定制并发类
1、定制ThreadPoolExecutor类
public class MyExecutor extends ThreadPoolExecutor { private ConcurrentHashMap<String, Date> startTimes; public MyExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); startTimes = new ConcurrentHashMap<>(); } @Override public void shutdown() { System.out.printf("MyExecutor: Going to shutdown.\n"); System.out.printf("MyExecutor: Executed tasks: %d\n", getCompletedTaskCount()); System.out.printf("MyExecutor: Running tasks: %d\n", getActiveCount()); System.out.printf("MyExecutor: Pending tasks: %d\n", getQueue().size()); super.shutdown(); } @Override public List<Runnable> shutdownNow() { System.out.printf("MyExecutor: Going to immediately shutdown.\n"); System.out.printf("MyExecutor: Executed tasks: %d\n", getCompletedTaskCount()); System.out.printf("MyExecutor: Running tasks: %d\n", getActiveCount()); System.out.printf("MyExecutor: Pending tasks: %d\n", getQueue().size()); return super.shutdownNow(); } @Override protected void beforeExecute(Thread t, Runnable r) { System.out.printf("MyExecutor: A task is beginning: %s: %s\n", t.getName(), r.hashCode()); startTimes.put(String.valueOf(r.hashCode()), new Date()); } @Override protected void afterExecute(Runnable r, Throwable t) { Future<?> result = (Future<?>)r; try { System.out.printf("****************************************\n"); System.out.printf("MyExecutor: A task is finishing.\n"); System.out.printf("MyExecutor: Result: %s\n", result.get()); Date startDate = startTimes.remove(String.valueOf(r.hashCode())); Date finishDate = new Date(); long diff = finishDate.getTime() - startDate.getTime(); System.out.printf("****************************************\n"); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } public class SleepTwoSecondsTask implements Callable<String> { public String call() throws Exception { TimeUnit.SECONDS.sleep(2); return new Date().toString(); } } public class Main { public static void main(String[] args) { MyExecutor myExecutor = new MyExecutor(2, 4, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>()); List<Future<String>> results = new ArrayList<>(); for(int i=0; i<10; i++) { SleepTwoSecondsTask task = new SleepTwoSecondsTask(); Future<String> result = myExecutor.submit(task); results.add(result); } for(int i=0; i<5; i++) { try { String result = results.get(i).get(); System.out.printf("Main: Result for Task %d: %s\n", i, result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } myExecutor.shutdown(); for(int i=5; i<10; i++) { try { String result = results.get(i).get(); System.out.printf("Main: Result for Task %d: %s\n", i, result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } try { myExecutor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: End of the program.\n"); } }
2、实现基于优先级的Executor类
public class MyPriorityTask implements Runnable, Comparable<MyPriorityTask> { private int priority; private String name; public MyPriorityTask(String name, int priority) { this.name = name; this.priority = priority; } public int getPriority() { return priority; } @Override public int compareTo(MyPriorityTask o) { if(this.getPriority() < o.getPriority()) { return 1; } if(this.getPriority() > o.getPriority()) { return -1; } return 0; } @Override public void run() { System.out.printf("MyPriorityTask: %s Priority: %d\n", name, priority); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 1, TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>()); for(int i=0; i<4; i++) { MyPriorityTask task = new MyPriorityTask("Task " + i, i); executor.execute(task); } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } for(int i=4; i<8; i++) { MyPriorityTask task = new MyPriorityTask("Task " + i, i); executor.execute(task); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: End of the program.\n"); } }
3、实现ThreadFactory接口生成定制线程
public class MyThread extends Thread { private Date creationDate; private Date startDate; private Date finishDate; public MyThread(Runnable target, String name) { super(target, name); setCreationDate(); } @Override public void run() { setStartDate(); super.run(); setFinishDate(); } public void setCreationDate() { creationDate = new Date(); } public void setStartDate() { startDate = new Date(); } public void setFinishDate() { finishDate = new Date(); } public long getExecutionTime() { return finishDate.getTime() - startDate.getTime(); } @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append(getName()); buffer.append(": "); buffer.append(" Creation Date: "); buffer.append(creationDate); buffer.append(": Running time: "); buffer.append(getExecutionTime()); buffer.append(" Milliseconds."); return buffer.toString(); } } public class MyThreadFactory implements ThreadFactory { private int counter; private String prefix; public MyThreadFactory(String prefix) { this.prefix = prefix; counter = 1; } @Override public Thread newThread(Runnable r) { MyThread myThread = new MyThread(r, prefix + "-" + counter); counter++; return myThread; } } public class MyTask implements Runnable { @Override public void run() { try { TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); } } } public class Main { public static void main(String[] args) throws InterruptedException { MyThreadFactory myThreadFactory = new MyThreadFactory("MyThreadFactory"); MyTask task = new MyTask(); Thread thread = myThreadFactory.newThread(task); thread.start(); thread.join(); System.out.printf("Main: THread information.\n"); System.out.printf("%s\n", thread); System.out.printf("Main: End of the example.\n"); } }
4、在Executor对象中使用ThreadFactory
public class Main { public static void main(String[] args) throws InterruptedException { MyThreadFactory threadFactory = new MyThreadFactory("MyThreadFactory"); ExecutorService executor = Executors.newCachedThreadPool(threadFactory); MyTask task = new MyTask(); executor.submit(task); executor.shutdown(); executor.awaitTermination(1, TimeUnit.DAYS); System.out.printf("Main: End of the program.\n"); } } public class MyThreadFactory implements ThreadFactory { private int counter; private String prefix; public MyThreadFactory(String prefix) { this.prefix = prefix; counter = 1; } @Override public Thread newThread(Runnable r) { MyThread myThread = new MyThread(r, prefix + "-" + counter); counter++; return myThread; } } public class MyThread extends Thread { private Date creationDate; private Date startDate; private Date finishDate; public MyThread(Runnable target, String name) { super(target, name); setCreationDate(); } @Override public void run() { setStartDate(); super.run(); setFinishDate(); } public void setCreationDate() { creationDate = new Date(); } public void setStartDate() { startDate = new Date(); } public void setFinishDate() { finishDate = new Date(); } public long getExecutionTime() { return finishDate.getTime() - startDate.getTime(); } @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append(getName()); buffer.append(": "); buffer.append(" Creation Date: "); buffer.append(creationDate); buffer.append(": Running time: "); buffer.append(getExecutionTime()); buffer.append(" Milliseconds."); return buffer.toString(); } } public class Main { public static void main(String[] args) throws InterruptedException { MyThreadFactory myThreadFactory = new MyThreadFactory("MyThreadFactory"); MyTask task = new MyTask(); Thread thread = myThreadFactory.newThread(task); thread.start(); thread.join(); System.out.printf("Main: THread information.\n"); System.out.printf("%s\n", thread); System.out.printf("Main: End of the example.\n"); } }
5、定制运行在定时线程池中的任务
public class MyScheduledTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> { private RunnableScheduledFuture<V> task; private ScheduledThreadPoolExecutor executor; private long period; private long startDate; public MyScheduledTask(Runnable runnable, V result, RunnableScheduledFuture<V> task, ScheduledThreadPoolExecutor executor) { super(runnable, result); this.task = task; this.executor = executor; } @Override public long getDelay(TimeUnit unit) { if(!isPeriodic()) { return task.getDelay(unit); } else { if(startDate == 0) { return task.getDelay(unit); } else { Date now = new Date(); long delay = startDate - now.getTime(); return unit.convert(delay, TimeUnit.MILLISECONDS); } } } @Override public int compareTo(Delayed o) { return task.compareTo(o); } @Override public boolean isPeriodic() { return task.isPeriodic(); } @Override public void run() { if(isPeriodic() && (!executor.isShutdown())) { Date now = new Date(); startDate = now.getTime() + period; executor.getQueue().add(this); } System.out.printf("Pre-MyScheduledTask: %s\n", new Date()); System.out.printf("MyScheduledTask: Is Periodic: %s\n", isPeriodic()); super.runAndReset(); System.out.printf("Post-MyScheduledTask: %s\n", new Date()); } public void setPeriod(long period) { this.period = period; } } public class MyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor { public MyScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize); } @Override protected<V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) { MyScheduledTask<V> myTask = new MyScheduledTask<V>(runnable, null, task, this); return myTask; } @Override public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { ScheduledFuture<?> task = super.scheduleAtFixedRate(command, initialDelay, period, unit); MyScheduledTask<?> myTask = (MyScheduledTask<?>) task; myTask.setPeriod(TimeUnit.MILLISECONDS.convert(period, unit)); return task; } } public class Task implements Runnable { @Override public void run() { System.out.printf("Task: Begin.\n"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Task: End.\n"); } } public class Main { public static void main(String[] args) throws Exception { MyScheduledThreadPoolExecutor executor = new MyScheduledThreadPoolExecutor(2); Task task = new Task(); System.out.printf("Main: %s\n", new Date()); executor.schedule(task, 1, TimeUnit.SECONDS); TimeUnit.SECONDS.sleep(3); task = new Task(); System.out.printf("Main: %s\n", new Date()); executor.scheduleAtFixedRate(task, 1, 3, TimeUnit.SECONDS); TimeUnit.SECONDS.sleep(10); executor.shutdown(); executor.awaitTermination(1, TimeUnit.DAYS); System.out.printf("Main: End of the program.\n"); } }
6、通过实现ThreadFactory接口为Fork/Join框架生成定制线程
public class MyWorkerThread extends ForkJoinWorkerThread { private static ThreadLocal<Integer> taskCounter = new ThreadLocal<Integer>(); protected MyWorkerThread(ForkJoinPool pool) { super(pool); } @Override protected void onStart() { super.onStart(); System.out.printf("MyWorkerTherad %d: Initializing task counter.\n", getId()); taskCounter.set(0); } @Override protected void onTermination(Throwable exception) { System.out.printf("MyWorkerThread %d: %d\n", getId(), taskCounter.get()); super.onTermination(exception); } public void addTask() { int counter = taskCounter.get().intValue(); counter++; taskCounter.set(counter); } } public class MyWorkerThreadFactory implements ForkJoinWorkerThreadFactory { @Override public ForkJoinWorkerThread newThread(ForkJoinPool pool) { return new MyWorkerThread(pool); } } public class MyRecursiveTask extends RecursiveTask<Integer> { private int array[]; private int start, end; public MyRecursiveTask(int array[], int start, int end) { this.array = array; this.start = start; this.end = end; } @Override protected Integer compute() { Integer ret; MyWorkerThread thread = (MyWorkerThread)Thread.currentThread(); thread.addTask(); if (end - start > 100) { int mid = (start + end) / 2; MyRecursiveTask task1 = new MyRecursiveTask(array, start, mid); MyRecursiveTask task2 = new MyRecursiveTask(array, mid, end); invokeAll(task1, task2); ret = addResults(task1, task2); } else { int add = 0; for (int i = start; i < end; i++) { add += array[i]; } ret = new Integer(add); } try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } return ret; } private Integer addResults(MyRecursiveTask task1, MyRecursiveTask task2) { int value; try { value = task1.get().intValue() + task2.get().intValue(); } catch (InterruptedException e) { e.printStackTrace(); value = 0; } catch (ExecutionException e) { e.printStackTrace(); value = 0; } try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } return value; } } public class Main { public static void main(String[] args) throws Exception { MyWorkerThreadFactory factory = new MyWorkerThreadFactory(); ForkJoinPool pool = new ForkJoinPool(4, factory, null, false); int array[] = new int[100000]; for(int i=0; i<array.length; i++) { array[i] = 1; } MyRecursiveTask task = new MyRecursiveTask(array, 0, array.length); pool.execute(task); task.join(); pool.shutdown(); pool.awaitTermination(1, TimeUnit.DAYS); System.out.printf("Main: Result: %d\n", task.get()); System.out.printf("Main: End of the program\n"); } }
7、定制运行在Fork/Join框架中的任务
public abstract class MyWorkerTask extends ForkJoinTask<Void> { private String name; public MyWorkerTask(String name) { this.name = name; } @Override public Void getRawResult() { return null; } @Override protected void setRawResult(Void value) { } @Override protected boolean exec() { Date startDate = new Date(); compute(); Date finishDate = new Date(); long diff = finishDate.getTime() - startDate.getTime(); System.out.printf("MyWorkerTask: %s: %d Milliseconds to complete.\n", name, diff); return true; } public String getName() { return name; } protected abstract void compute(); } public class Task extends MyWorkerTask { private int array[]; private int start; private int end; public Task(String name, int array[], int start, int end) { super(name); this.array = array; this.start = start; this.end = end; } protected void compute() { if(end-start > 100) { int mid = (end+start) / 2; Task task1 = new Task(this.getName() + "1", array, start, mid); Task task2 = new Task(this.getName() + "2", array, mid, end); invokeAll(task1, task2); } else { for(int i=start; i<end; i++) { array[i]++; } } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String[] args) { int array[] = new int[10000]; ForkJoinPool pool = new ForkJoinPool(); Task task = new Task("Task", array, 0, array.length); pool.invoke(task); pool.shutdown(); System.out.printf("Main: End of the program.\n"); } }
8、实现定制Lock类
public class MyAbstractQueuedSynchronizer extends AbstractQueuedSynchronizer { private AtomicInteger state; public MyAbstractQueuedSynchronizer() { state = new AtomicInteger(0); } @Override protected boolean tryAcquire(int arg) { return state.compareAndSet(0, 1); } @Override protected boolean tryRelease(int arg) { return state.compareAndSet(1, 0); } } public class MyLock implements Lock { private AbstractQueuedSynchronizer sync; public MyLock() { sync = new MyAbstractQueuedSynchronizer(); } @Override public void lock() { sync.acquire(1); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock() { try { return sync.tryAcquireNanos(1, 1000); } catch (InterruptedException e) { e.printStackTrace(); return false; } } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, TimeUnit.NANOSECONDS.convert(time, unit)); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.new ConditionObject(); } } public class Task implements Runnable { private MyLock lock; private String name; public Task(String name, MyLock lock) { this.lock = lock; this.name = name; } @Override public void run() { lock.lock(); System.out.printf("Task: %s: Take the lock\n", name); try { TimeUnit.SECONDS.sleep(2); System.out.printf("Task: %s: Free the lock\n", name); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class Main { public static void main(String[] args) { MyLock lock = new MyLock(); for(int i=0; i<10; i++) { Task task = new Task("Task-" + i, lock); Thread thread = new Thread(task); thread.start(); } boolean value; do { try { value = lock.tryLock(1, TimeUnit.SECONDS); if(!value) { System.out.printf("Main: Trying to get the Lock\n"); } } catch (InterruptedException e) { e.printStackTrace(); value = false; } } while (!value); System.out.printf("Main: Got the lock\n"); lock.unlock(); System.out.printf("Main: End of the program\n"); } }
9、实现基于优先级的传输队列
public class MyPriorityTransferQueue<E> extends PriorityBlockingQueue<E> implements TransferQueue<E> { private AtomicInteger counter; private LinkedBlockingQueue<E> transfered; private ReentrantLock lock; public MyPriorityTransferQueue() { counter = new AtomicInteger(0); lock = new ReentrantLock(); transfered = new LinkedBlockingQueue<E>(); } @Override public boolean tryTransfer(E e) { lock.lock(); boolean value; if(counter.get() == 0) { value = false; } else { put(e); value = true; } lock.unlock(); return value; } @Override public void transfer(E e) throws InterruptedException { lock.lock(); if(counter.get() != 0) { put(e); lock.unlock(); } else { transfered.add(e); lock.unlock(); synchronized (e) { e.wait(); } } } @Override public boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException { lock.lock(); if(counter.get() != 0) { put(e); lock.unlock(); return true; } else { transfered.add(e); long newTimeout = TimeUnit.MILLISECONDS.convert(timeout, unit); lock.unlock(); e.wait(newTimeout); lock.lock(); if(transfered.contains(e)) { transfered.remove(e); lock.unlock(); return false; } else { lock.unlock(); return true; } } } @Override public boolean hasWaitingConsumer() { return (counter.get() != 0); } @Override public int getWaitingConsumerCount() { return counter.get(); } @Override public E take() throws InterruptedException { lock.lock(); counter.incrementAndGet(); E value = transfered.poll(); if(value == null) { lock.unlock(); value = super.take(); lock.lock(); } else { synchronized (value) { value.notify(); } } counter.decrementAndGet(); lock.unlock(); return value; } } public class Event implements Comparable<Event> { private String thread; private int priority; public Event(String thread, int priority) { this.thread = thread; this.priority = priority; } public String getThread() { return thread; } public int getPriority() { return priority; } public int compareTo(Event e) { if(this.priority > e.getPriority()) { return -1; } else if(this.priority < e.getPriority()) { return 1; } else { return 0; } } } public class Producer implements Runnable { private MyPriorityTransferQueue<Event> buffer; public Producer(MyPriorityTransferQueue<Event> buffer) { this.buffer = buffer; } @Override public void run() { for(int i=0; i<100; i++) { Event event = new Event(Thread.currentThread().getName(), i); buffer.put(event); } } } public class Consumer implements Runnable { private MyPriorityTransferQueue<Event> buffer; public Consumer(MyPriorityTransferQueue<Event> buffer) { this.buffer = buffer; } @Override public void run() { for(int i=0; i<1002; i++) { try { Event value = buffer.take(); System.out.printf("Consumer: %s %d\n", value.getThread(), value.getPriority()); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) throws InterruptedException { MyPriorityTransferQueue<Event> buffer = new MyPriorityTransferQueue<>(); Producer producer = new Producer(buffer); Thread producerThreads[] = new Thread[10]; for(int i=0; i<producerThreads.length; i++) { producerThreads[i] = new Thread(producer); producerThreads[i].start(); } Consumer consumer = new Consumer(buffer); Thread consumerThread = new Thread(consumer); consumerThread.start(); System.out.printf("Main: Buffer: Consumer count: %d\n", buffer.getWaitingConsumerCount()); Event myEvent = new Event("Core Event", 0); buffer.transfer(myEvent); System.out.printf("Main: My Event has been transfered.\n"); for (int i=0; i<producerThreads.length; i++) { try { producerThreads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } TimeUnit.SECONDS.sleep(1); System.out.printf("Main: Buffer: Consumer count: %d\n", buffer.getWaitingConsumerCount()); myEvent = new Event("Core Event 2", 0); buffer.transfer(myEvent); consumerThread.join(); System.out.printf("Main: End of the program\n"); } }
10、实现自己的原子对象
public class ParkingCounter extends AtomicInteger { private int maxNumber; public ParkingCounter(int maxNumber) { set(0); this.maxNumber = maxNumber; } public boolean carIn() { for(;;) { int value = get(); if(value == maxNumber) { System.out.printf("ParkingCounter: The parking lot is full.\n"); return false; } else { int newValue = value + 1; boolean changed = compareAndSet(value, newValue); if(changed) { System.out.printf("ParkingCounter: A car has entered.\n"); return true; } } } } public boolean carOut() { for(;;) { int value = get(); if(value == 0) { System.out.printf("ParkingCounter: The parking lot is empty.\n"); return false; } else { int newValue = value - 1; boolean changed = compareAndSet(value, newValue); if(changed) { System.out.printf("ParkingCounter: A car has gone out.\n"); return true; } } } } } public class Sensor1 implements Runnable { private ParkingCounter counter; public Sensor1(ParkingCounter counter) { this.counter = counter; } @Override public void run() { counter.carIn(); counter.carIn(); counter.carIn(); counter.carIn(); counter.carOut(); counter.carOut(); counter.carOut(); counter.carIn(); counter.carIn(); counter.carIn(); } } public class Sensor2 implements Runnable { private ParkingCounter counter; public Sensor2(ParkingCounter counter) { this.counter = counter; } @Override public void run() { counter.carIn(); counter.carOut(); counter.carOut(); counter.carIn(); counter.carIn(); counter.carIn(); counter.carIn(); counter.carIn(); counter.carIn(); } } public class Main { public static void main(String[] args) { ParkingCounter counter = new ParkingCounter(5); Sensor1 sensor1 = new Sensor1(counter); Sensor2 sensor2 = new Sensor2(counter); Thread thread1 = new Thread(sensor1); Thread thread2 = new Thread(sensor2); thread1.start(); thread2.start(); System.out.printf("Main: Number of cars: %d\n", counter.get()); System.out.printf("Main: End of the program.\n"); } }
八、测试并发应用程序
1、监控Lock接口
public class MyLock extends ReentrantLock { public String getOwnerName() { if(this.getOwner() == null) { return "None"; } return this.getOwner().getName(); } public Collection<Thread> getThreads() { return this.getQueuedThreads(); } } public class Task implements Runnable { private Lock lock; public Task(Lock lock) { this.lock = lock; } @Override public void run() { for(int i=0; i<5; i++) { lock.lock(); System.out.printf("%s: Get the Lock.\n", Thread.currentThread().getName()); try { TimeUnit.MILLISECONDS.sleep(500); System.out.printf("%s Free the Lock.\n", Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } } public class Main { public static void main(String args[]) throws Exception { MyLock lock = new MyLock(); Thread threads[] = new Thread[5]; for(int i=0; i<5; i++) { Task task = new Task(lock); threads[i] = new Thread(task); threads[i].start(); } for (int i=0; i<15; i++) { System.out.printf("Main: Logging the Lock\n"); System.out.printf("******************************\n"); System.out.printf("Lock: Owner: %s\n", lock.getOwnerName()); System.out.printf("Lock: Queue Threads: %s\n", lock.hasQueuedThreads()); if(lock.hasQueuedThreads()) { System.out.printf("Lock: Queue Length: %d\n", lock.getQueueLength()); System.out.printf("Lock: Queued Threads: "); Collection<Thread> lockedThreads = lock.getThreads(); for(Thread lockedThread : lockedThreads) { System.out.printf("%s ", lockedThread.getName()); } System.out.printf("\n"); } System.out.printf("Lock: Fairness: %s\n", lock.isFair()); System.out.printf("Lock: Locked: %s\n", lock.isLocked()); System.out.printf("****************************\n"); TimeUnit.SECONDS.sleep(1); } } }
2、监控Phaser类
public class Task implements Runnable { private int time; private Phaser phaser; public Task(int time, Phaser phaser) { this.time = time; this.phaser = phaser; } @Override public void run() { phaser.arrive(); System.out.printf("%s: Entering phase 1.\n", Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Finishing phase 1.\n", Thread.currentThread().getName()); phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Entering phase 2.\n", Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Finishing phase 2.\n", Thread.currentThread().getName()); phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Entering phase 3.\n", Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Finishing phase 3.\n", Thread.currentThread().getName()); phaser.arriveAndDeregister(); } } public class Main { public static void main(String args[]) throws Exception { Phaser phaser = new Phaser(3); for (int i=0; i<3; i++) { Task task = new Task(i+1, phaser); Thread thread = new Thread(task); thread.start(); } for (int i=0; i<10; i++) { System.out.printf("********************\n"); System.out.printf("Main: Phaser Log\n"); System.out.printf("Main: Phaser: Phase: %d\n", phaser.getPhase()); System.out.printf("Main: Phaser: Registered Parties: %d\n", phaser.getRegisteredParties()); System.out.printf("Main: Phaser: Arrived Parties: %d\n", phaser.getArrivedParties()); System.out.printf("Main: Phaser: Unarrived Parties: %d\n", phaser.getUnarrivedParties()); System.out.printf("********************\n"); TimeUnit.SECONDS.sleep(1); } } }
3、监控执行器框架
public class Task implements Runnable { private long milliseconds; public Task (long milliseconds) { this.milliseconds = milliseconds; } @Override public void run() { System.out.printf("%s: Begin\n", Thread.currentThread().getName()); try { TimeUnit.MILLISECONDS.sleep(milliseconds); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: End\n", Thread.currentThread().getName()); } } public class Main { public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool(); Random random = new Random(); for (int i=0; i<10; i++) { Task task = new Task(random.nextInt(10000)); executor.submit(task); } for (int i=0; i<5; i++) { showLog(executor); TimeUnit.SECONDS.sleep(1); } executor.shutdown(); for (int i=0; i<5; i++) { showLog(executor); TimeUnit.SECONDS.sleep(1); } executor.awaitTermination(1, TimeUnit.DAYS); System.out.printf("Main: End of the program.\n"); } private static void showLog(ThreadPoolExecutor executor) { System.out.printf("***********************"); System.out.printf("Main: Executor Log"); System.out.printf("Main: Executor: Core Pool Size: %d\n", executor.getPoolSize()); System.out.printf("Main: Executor: Pool Size: %d\n", executor.getPoolSize()); System.out.printf("Main: Executor: Active Count: %d\n", executor.getActiveCount()); System.out.printf("Main: Executor: Task Count: %d\n", executor.getCompletedTaskCount()); System.out.printf("Main: Executor: Completed Task Count: %d\n", executor.getCompletedTaskCount()); System.out.printf("Main: Executor: Shutdown: %d\n", executor.isShutdown()); System.out.printf("Main: Executor: Terminating: %d\n", executor.isTerminating()); System.out.printf("Main: Executor: Terminated: %d\n", executor.isTerminated()); System.out.printf("***********************"); } }
4、监控Fork/Join池
public class Task extends RecursiveAction { private int array[]; private int start; private int end; public Task(int array[], int start, int end) { this.array = array; this.start = start; this.end = end; } protected void compute() { if(end-start > 100) { int mid = (start+end) / 2; Task task1 = new Task(array, start, mid); Task task2 = new Task(array, mid, end); task1.fork(); task2.fork(); task1.join(); task2.join(); } else { for(int i=start; i<end; i++) { array[i]++; try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } } } } public class Main { public static void main(String[] args) throws InterruptedException { ForkJoinPool pool = new ForkJoinPool(); int array[] = new int[10000]; Task task1 = new Task(array, 0, array.length); pool.execute(task1); while(!task1.isDone()) { showLog(pool); TimeUnit.SECONDS.sleep(1); } pool.shutdown(); pool.awaitTermination(1, TimeUnit.DAYS); showLog(pool); System.out.printf("Main: End of the program.\n"); } private static void showLog(ForkJoinPool pool) { System.out.printf("**********************\n"); System.out.printf("Main: Fork/Join Pool log\n"); System.out.printf("Main: Fork/Join Pool: Parallelism: %d\n", pool.getParallelism()); System.out.printf("Main: Fork/Join Pool: Pool Size: %d\n", pool.getPoolSize()); System.out.printf("Main: Fork/Join Pool: Active Thread Count: %d\n", pool.getActiveThreadCount()); System.out.printf("Main: Fork/Join Pool: Running Thread Count: %d\n", pool.getRunningThreadCount()); System.out.printf("Main: Fork/Join Pool: Queued Submission: %d\n", pool.getQueuedSubmissionCount()); System.out.printf("Main: Fork/Join Pool: Queued Tasks: %d\n", pool.getQueuedTaskCount()); System.out.printf("Main: Fork/Join Pool: Steal Count: %d\n", pool.getStealCount()); System.out.printf("Main: Fork/Join Pool: Terminated: %s\n", pool.isTerminated()); System.out.printf("**********************\n"); } }
5、输出高效的日志信息
public class MyFormatter extends Formatter { @Override public String format(LogRecord record) { StringBuilder sb = new StringBuilder(); sb.append("[" + record.getLevel() + "] - "); sb.append(new Date(record.getMillis()) + " : "); sb.append(record.getSourceClassName() + "." + record.getSourceMethodName() + " : "); sb.append(record.getMessage() + "\n"); return sb.toString(); } } public class MyLogger { private static Handler handler; public static Logger getLogger(String name) { Logger logger = Logger.getLogger(name); logger.setLevel(Level.ALL); try { if(handler == null) { handler = new FileHandler("recipe8.log"); Formatter format = new MyFormatter(); handler.setFormatter(format); } if(logger.getHandlers().length == 0) { logger.addHandler(handler); } } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return logger; } } public class Task implements Runnable { @Override public void run() { Logger logger = MyLogger.getLogger(this.getClass().getName()); logger.entering(Thread.currentThread().getName(), "run()"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } logger.exiting(Thread.currentThread().getName(), "run()", Thread.currentThread()); } } public class Main { public static void main(String[] args) { Logger logger = MyLogger.getLogger("Core"); logger.entering("Core", "main()", args); Thread threads[] = new Thread[5]; for(int i=0; i<threads.length; i++) { logger.log(Level.INFO, "Launching thread: " + i); Task task = new Task(); threads[i] = new Thread(task); logger.log(Level.INFO, "Thread created: ", threads[i].getName()); threads[i].start(); } logger.log(Level.INFO, "Ten Threads created." + "Waiting for its finalization"); for(int i=0; i<threads.length; i++) { try { threads[i].join(); logger.log(Level.INFO, "Thread has finished its execution", threads[i]); } catch (InterruptedException e) { logger.log(Level.SEVERE, "Exception", e); } } logger.exiting("Core", "main()"); } }