primefinder

需求

Prime Finder

For this homework assignment, you must:

Add a pending variable to the WorkQueue class to track unfinished work, and implement a finish() method that waits until there is no more pending work.

Implement the multithreaded findPrimes(int, int, int) method in PrimeFinder using a WorkQueue. There should be 1 task or Runnable object for each number being tested, and the run() method of these objects should use the isPrime(int) method.

Requirements

The official name of this homework is PrimeFinder. This should be the name you use for your Eclipse Java project and the name you use when running the homework test script.

See the Homework Guides for additional details on homework requirements and submission.

关键类实现

PrimeFinder

import java.util.TreeSet;

/**
 * Finds primes, with an inefficient single-threaded implementation made somewhat
 * less inefficient with multithreading using a work queue.
 * 
 * @author CS 212 Software Development
 * @author University of San Francisco
 * @version Spring 2021
 */
public class PrimeFinder {
	/**
	 * A terrible and naive approach to determining if a number is prime.
	 *
	 * @param number to test if prime
	 * @return true if the number is prime
	 */
	public static boolean isPrime(int number) {
		if (number < 2) {
			return false;
		}

		for (int i = number - 1; i > 1; i--) {
			if (number % i == 0) {
				return false;
			}
		}

		return true;
	}

	/*
	 * This is an intentionally TERRIBLE implementation to cause a long-running
	 * calculation. There really is no realistic use of this approach.
	 */

	/**
	 * Returns a collection of all primes less than or equal to the max value.
	 *
	 * @param max the maximum value to evaluate if prime
	 * @return all prime numbers found up to and including max
	 */
	public static TreeSet<Integer> trialDivision(int max) {
		TreeSet<Integer> primes = new TreeSet<Integer>();

		if (max > 0) {
			for (int i = 1; i <= max; i++) {
				if (isPrime(i)) {
					primes.add(i);
				}
			}
		}

		return primes;
	}

	/**
	 * Uses a work queue to find all primes less than or equal to the maximum
	 * value. The number of threads must be a positive number greater than or
	 * equal to 1.
	 *
	 * @param max the maximum value to evaluate if prime
	 * @param threads number of worker threads (must be positive)
	 * @return all prime numbers found up to and including max
	 */
	public static TreeSet<Integer> findPrimes(int max, int threads) {
		// TODO Fix this implementation (see trialDivision for starting point).
		TreeSet<Integer> primes = new TreeSet<Integer>();
		WorkQueue queue = new WorkQueue(threads);

		if (max > 0) {
			for (int i = 1; i <= max; i++) {
				queue.execute(new Task(i, primes));
			}
		}
		queue.join();

		return primes;
	}

	// TODO Add additional classes or methods as needed.
	public static class Task implements Runnable {
		private final int number;
		private final TreeSet<Integer> result;

		public Task(int number, TreeSet<Integer> result) {
			this.number = number;
			this.result = result;
		}

		@Override
		public void run() {
			if (isPrime(number)) {
				synchronized (result) {
					result.add(number);
				}
			}

		}

	}
	
	/**
	 * Demonstrates this class.
	 *
	 * @param args unused
	 */
	public static void main(String[] args) {
		int max = 100;
		int threads = 3;

		// see if the single and mutli threaded versions return the same result
		System.out.println("Comparing prime numbers:");
		System.out.println(trialDivision(max));
		System.out.println(findPrimes(max, threads));
		System.out.println();
	}
}

WorkQueue

import java.util.Arrays;
import java.util.LinkedList;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * A simple work queue implementation based on the IBM developerWorks article by
 * Brian Goetz. It is up to the user of this class to keep track of whether
 * there is any pending work remaining.
 *
 * @see <a href="https://www.ibm.com/developerworks/library/j-jtp0730/">
 * Java Theory and Practice: Thread Pools and Work Queues</a>
 * 
 * @author CS 212 Software Development
 * @author University of San Francisco
 * @version Spring 2021
 */
public class WorkQueue {
	// TODO Modify existing methods if necessary.

	// TODO Add new members and methods if necessary.
	public static int taskNum;

	private synchronized  void addTask() {
		taskNum ++ ;
	}

	private synchronized void deleteTask() {
		taskNum -- ;
	}
	
	/**
	 * Pool of worker threads that will wait in the background until work is
	 * available.
	 */
	private final Worker[] workers;

	/** Queue of pending work requests. */
	private final LinkedList<Runnable> queue;

	/** Used to signal the queue should be shutdown. */
	private volatile boolean shutdown;

	/** The default number of threads to use when not specified. */
	public static final int DEFAULT = 5;

	/** Logger used for this class. */
	private static final Logger log = LogManager.getLogger();
	
	/**
	 * Starts a work queue with the default number of threads.
	 *
	 * @see #WorkQueue(int)
	 */
	public WorkQueue() {
		this(DEFAULT);
	}

	/**
	 * Starts a work queue with the specified number of threads.
	 *
	 * @param threads number of worker threads; should be greater than 1
	 */
	public WorkQueue(int threads) {
		this.queue = new LinkedList<Runnable>();
		this.workers = new Worker[threads];

		shutdown = false;

		// start the threads so they are waiting in the background
		for (int i = 0; i < threads; i++) {
			workers[i] = new Worker();
			workers[i].start();
		}
		
		log.debug("Work queue initialized with {} worker threads.", workers.length);
	}

	/**
	 * Adds a work request to the queue. A thread will process this request when
	 * available.
	 *
	 * @param task work request (in the form of a {@link Runnable} object)
	 */
	public void execute(Runnable task) {
		synchronized (queue) {
			queue.addLast(task);
			addTask();
			queue.notifyAll();
		}
	}
	
	/**
	 * Waits for all pending work to be finished. Does not terminate the worker
	 * threads so that the work queue can continue to be used.
	 */
	public void finish() {
		// TODO Fix this method implementation.
		synchronized (queue) {
			while (taskNum > 0) {
				try {
					queue.wait();
				} catch (InterruptedException e) {
					System.err.println("Interrupted Exception!");
				}
			}
		}
	}

	/**
	 * Asks the queue to shutdown. Any unprocessed work will not be finished, but
	 * threads in-progress will not be interrupted.
	 */
	public void shutdown() {
		// safe to do unsynchronized due to volatile keyword
		shutdown = true;

		log.debug("Work queue triggering shutdown...");
		synchronized (queue) {
			queue.notifyAll();
		}
	}
	
	/**
	 * Similar to {@link Thread#join()}, waits for all the work to be finished
	 * and the worker threads to terminate. The work queue cannot be reused after
	 * this call completes.
	 */
	public void join() {
		finish();
		shutdown();
		
		for (Worker worker : workers) {
			try {
				worker.join();
			}
			catch (InterruptedException e) {
				System.err.println("Warning: Work queue interrupted while joining.");
				log.catching(Level.DEBUG, e);
				Thread.currentThread().interrupt();
			}
		}
		
		log.debug("All worker threads terminated.");
	}

	/**
	 * Returns the number of worker threads being used by the work queue.
	 *
	 * @return number of worker threads
	 */
	public int size() {
		return workers.length;
	}

	/**
	 * Waits until work is available in the work queue. When work is found, will
	 * remove the work from the queue and run it. If a shutdown is detected, will
	 * exit instead of grabbing new work from the queue. These threads will
	 * continue running in the background until a shutdown is requested.
	 */
	private class Worker extends Thread {
		/**
		 * Initializes a worker thread with a custom name.
		 */
		public Worker() {
			setName("Worker" + getName());
		}

		@Override
		public void run() {
			Runnable task = null;

			while (true) {
				synchronized (queue) {
					while (queue.isEmpty() && !shutdown) {
						try {
							log.debug("Work queue worker waiting...");
							queue.wait();
						}
						catch (InterruptedException e) {
							System.err.println("Warning: Work queue interrupted while waiting.");
							log.catching(Level.DEBUG, e);
							Thread.currentThread().interrupt();
						}
					}

					// exit while for one of two reasons:
					// (a) queue has work, or (b) shutdown has been called

					if (shutdown) {
						log.debug("Work queue worker shutting down...");
						break;
					}
					else {
						task = queue.removeFirst();
					}
				}
				deleteTask();
				synchronized (queue) {
					if (taskNum <= 0) {
						queue.notifyAll();
					}
				}

				try {
					log.debug("Work queue worker found work.");
					task.run();
				}
				catch (RuntimeException e) {
					// catch runtime exceptions to avoid leaking threads
					System.err.println("Warning: Work queue encountered an exception while running.");
					log.catching(Level.DEBUG, e);
				}
			}
		}
	}
	
	// TODO Remove main method when done testing!
	/**
	 * Demonstrates this class.
	 * 
	 * @param args unused
	 */
	public static void main(String[] args) {
		int threads = 3;
		
		Supplier<String> activeThreads = () -> {
			Thread[] found = new Thread[Thread.activeCount() * 2];
			Thread.enumerate(found);
			return Arrays.stream(found).filter(t -> t != null).map(Thread::getName).collect(Collectors.joining(", "));
		};
		
		// demonstrates the workers in the background
		WorkQueue demo = new WorkQueue(threads);
		
		// do a bit of work in the background
		demo.execute(() -> {
			try {
				Thread.sleep(100);
			}
			catch (InterruptedException e) {
				Thread.currentThread().interrupt();
			}
		});

		// finish, but do not shutdown
		demo.finish();
		
		// peek at the threads active in the system
		System.out.println("Estimated active threads before join(): " + activeThreads.get());
		
		// trigger threads to shutdown
		demo.join();
		
		// peek at the threads after shutdown and join
		System.out.println("Estimated active threads after join(): " + activeThreads.get());
		
		/*
		 * The thread named "main" runs the main method.
		 * 
		 * If you see any thread names starting with "ForkJoinPool", those
		 * are used internally. They could come from Log4j2 or JUnit.
		 * 
		 * If you see any thread names starting with "WorkerThread", those
		 * are likely your work queue threads.
		 * 
		 * If you see your work queue threads AFTER the join() call, something
		 * is not quite working with the finish and/or shutdown calls.
		 */
	}
}

源码地址

https://download.csdn.net/download/rainbowBear/16730962
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永远喜欢薇尔莉特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值