201621123008 《Java程序设计》 第11周学习总结

1. 本周学习总结

1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容。

2. 书面作业

本次PTA作业题集多线程

1. 源代码阅读:多线程程序BounceThread

1.1 BallRunnable类有什么用?为什么代码中需要调用Thread.sleep进行休眠?

分析: BallRunnable类实现了Runnable接口,其run方法包含线程执行体,该方法根据STEPS的值来控制绘制小球的次数,通过move方法来确定小球的位置。而使用sleep让线程进入阻塞状态,即,小球暂时停留,让人得以观察其运动轨迹。

1.2 Ball.java只做了两件事,这两件事分别是什么?BallComponent对象是干什么的?其内部的ArrayList有什么用?程序运行过程中,生成了几个BallComponent对象?该程序使用了多线程技术,每个小球是分别在不同的线程中进行绘制吗?

分析:

  • Ball.java:该类有两个方法:

  • public void move(Rectangle2D bounds):重绘小球时确定其位置。

  • public Ellipse2D getShape():得到一个Ellipse2D.Double对象,存储2D圆对象。

  • BallComponent对象:

  • 加小球,画小球

  • ArrayList用于存放加入的小球

  • 生成了一个BallComponent对象

  • 每点击一次start按钮就产生一个线程。每个小球在自己所属线程内进行绘制

1.3 选做:程序改写:程序运行时,每个小球都是从固定位置出发。如何改写该程序,使得当点击start时,每个小球可以从不同位置出发、以不同的步进移动?

Ball中的move方法进行修改。

    x=Math.random()*bounds.getMaxX();
     y=Math.random()*bounds.getMaxY();
     dx=Math.random()*5;
     dy=Math.random()*5;

1.4 选做:不同小球的移动轨迹一模一样。改造程序,使得每个小球运行轨迹不完全一样,比如有的可以走余弦轨迹、有的可以走方波轨迹、有的走布朗运动、有的走五角星,等等。

2. 实验总结:题集(多线程)

2.1 题目:Thread、PrintTask、Runnable与匿名内部类。并回答:a)通过定义Runnable接口的实现类来实现多线程程序比通过继承自Thread类实现多线程程序有何好处?b) 6-1,6-3,6-11实验总结。

分析:若我们创建的类继承自Thread那么该类就是一个Thread,若我们通过实现Runnable接口,则我们创建的类还可以再继承自其他类,总的来说操作Runnable接口的好处就是比较有弹性。

总结:

6-1:通过继承Thread并重写run方法来创建线程,Thread本身就实现了Runnable接口

6-3:使用Thread.currentThread()获得当前执行线程对象,从而获得线程名

6-11:通过实现Runnable接口,并重写run方法来创建线程。

2.2 使用Lambda表达式改写6-3

  Thread t1 = new Thread(()-> {
      
        		System.out.println(mainThreadName);
        		System.out.println(Thread.currentThread().getName());
        		System.out.println(Arrays.toString(Thread.class.getInterfaces()));
        	
        });

2.3 题目:6-2(Runnable与停止线程)。回答:需要怎样才能正确地停止一个运行中的线程?

runcall方法执行完后线程正常死亡,由于stop方法易产生错误,故可以在runcall方法中依据标志位进行循环控制实现线程的停止。

2.4 选做:6-8(CountDownLatch)实验总结

总结:

  • CountDownLatch:一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

  • ExecutorService:提交任务,并进行调度执行。通过 Executors 类来创建的线程池的类型:拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待, Executors.newFixedThreadPool()

2.5 选做:6-9(集合同步问题)实验总结

总结: 使用Collections.synchronizedList(new ArrayList<Integer>());将传入的操作对象打包,返回线程安全的对象

2.6 选做:较难:6-10(Callable),并回答为什么有Runnable了还需要Callable?实验总结。

总结: 其实CallableRunnable都是将方法包装成线程执行体,区别就是Callable中的call方法具有返回值,可以声明抛出异常对象。正是利用这个性质我们可以通过call方法返回n对应的斐波那契值,关联Fututr得到返回值,继而计算斐波那契数列的前n项和。

3. 互斥访问

3.1 修改TestUnSynchronizedThread.java源代码使其可以同步访问。(关键代码截图,需出现学号)

Counter类中的方法进行了修改
修改后的代码

class Counter {
	private volatile static int id = 0;

	public synchronized static void addId() {
		id++;
	}

	public synchronized static void subtractId() {
		id--;
	}

	public static int getId() {
		return id;
	}
}

运行结果

3.2 选做:进一步使用执行器改进相应代码(关键代码截图,需出现学号)

参考资料:Java多线程之Executor、ExecutorService、Executors、Callable、Future与FutureTask

/**
 * 
 * @author 周文华
 *
 */
public class TestUnSynchronizedThread {

	public static void main(String[] args) throws InterruptedException {

		List<Callable<Integer>> taskList = new ArrayList<>();
		ExecutorService exec = Executors.newSingleThreadScheduledExecutor();
		for (int i = 0; i < 6; i++) {
			if (i < 3)
				taskList.add(new Adder());
			else
				taskList.add(new Subtracter());
		}
		List<Future<Integer>>list=exec.invokeAll(taskList);
		exec.shutdown();
		try {
			System.out.println(list.get(list.size()-1).get());
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		System.out.println("main end");
	}
}

class Adder implements Callable<Integer> {

	@Override
	public Integer call() {
		for (int i = 0; i < 10000; i++)
			Counter.addId();
		System.out.println(Thread.currentThread().getName() + " end");
		return Counter.getId();
	}
}

class Subtracter implements Callable<Integer> {

	@Override
	public Integer call() {
		for (int i = 0; i < 10000; i++)
			Counter.subtractId();
		System.out.println(Thread.currentThread().getName() + " end");
		return Counter.getId();
	}
}

class Counter {
	private volatile static int id = 0;

	public synchronized static void addId() {
		id++;
	}

	public synchronized static void subtractId() {
		id--;
	}

	public static int getId() {
		return id;
	}
}

运行结果

4. 互斥访问与同步访问

完成题集6-4(互斥访问)与6-5(同步访问)

4.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法可以使用synchronized实现互斥同步访问,使用代码说明(请出现相关代码及学号)?

分析:还可以通过同步代码块实现互斥访问

代码:

package Test02;

import javax.swing.plaf.SliderUI;

public class SynchronizedTest {

    //锁定方法,加锁对象SynchronizedTest实例
	public synchronized void method1() {
		System.out.println("method 1 ...");
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

    //锁定SynchronizedTest对象
	public void method2() {
		synchronized (this) {
			System.out.println("method 2 ...");
		}
	}

    //方法内部进行锁定,锁定对象为str
	public void method3() {
		String str = "mehtod 3 ...";
		synchronized (str) {
			System.out.println(str);

		}
	}

	public static void main(String[] args) {
		SynchronizedTest test = new SynchronizedTest();
		Thread th1 = new Thread(new Runnable() {

			@Override
			public void run() {
				test.method1();

			}
		});
		Thread th2 = new Thread(new Runnable() {

			@Override
			public void run() {
				test.method2();

			}
		});

		Thread th3 = new Thread(new Runnable() {

			@Override
			public void run() {
				test.method3();

			}
		});
		th1.start();
		th2.start();
		th3.start();
	}
}

4.2 同步代码块与同步方法有何区别?

分析:由上例三个method可以看出使用同步代码块可以更实现精细的锁定,我们可以锁定只会发生竞速状况的区块。

4.3 实现互斥访问的原理是什么?请使用对象锁概念并结合相应的代码块进行说明。当程序执行synchronized同步代码块或者同步方法时,线程的状态是怎么变化的?

分析:我们知道在线程是并发进行的,即在同一时刻只能有一条指令执行,但多个线程指令快速轮换执行,CPU执行速度很快,使得在宏观上有同时执行的效果。线程同步最经典的例子是存取取钱的问题,若采用并发线程,进行取钱操作,很可能由于线程调度的不确定性,使的取出的钱数大于账户余额,这时我们就需要一个同步监视器了,在我们进行取钱操作之前得先获得同步监视器的锁定,即获得一个共有资源的使用权,使用期间其他线程无法对该资源进行操作,使用完之后再把锁交出,让其他线程去竞争使用权,从而保证了线程安全性。

4.4 Java多线程中使用什么关键字实现线程之间的通信,进而实现线程的协同工作?

分析:可以使用Object类的wait(),notify(),notifyAll(),但是这些方法必须由同步监视器对象来调用。

wait():导致当前线程等待,直到其他线程调用该同步监视器的notify(),notifyAll()方法。

notify():唤醒在此同步监视器上等待的单个线程,注意,只有在当前线程放弃了同步监测器的锁定之后(使用wait()方法后),才可以执行被唤醒的线程,选择随意。

notifyAll():唤醒所有在此监视器上等待的线程其他与notify()类似。

5. 线程间的合作:生产者消费者问题

5.1 运行MyProducerConsumerTest.java。正常运行结果应该是仓库还剩0个货物。多运行几次,观察结果,并回答:结果正常吗?哪里不正常?为什么?

分析:分析代码可知,该程序功能是放入先100个货物再取出100个货物,结果应当为0,执行几次后发现结果并不是正确的,应为仓库的容量为10,当仓库满时就应该停止添加操作,唤醒取出操作,而程序没有做这些操作,只是一个线程只负责添加,一个线程只负责取出,两线程之间没有实现通信。

5.2 使用synchronized, wait, notify解决该问题(关键代码截图,需出现学号)

public synchronized void add(String t) {
		if (repo.size() >= capacity) {
			System.out.println("仓库已满!无法添加货物。");
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			repo.add(t);
			notify();
		}
		
	}
	public synchronized void remove() {
		if (repo.size() <= 0) {
			System.out.println("仓库无货!无法从仓库取货");
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			repo.remove(0);
			notify();
		}
	}

5.3 选做:使用Lock与Condition对象解决该问题。

class Repository {// 存放字符串的仓库
	private int capacity = 10;// 仓库容量默认为10
	private List<String> repo = new ArrayList<String>();// repo(仓库),最多只能放10个
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();

	public void add(String t) {
		try {
			lock.lock();
			while(repo.size() >= capacity) {
					try {
						condition.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			} 
				repo.add(t);
				condition.signal();
		
		} finally {
			lock.unlock();}
	}

	public void remove() {
		try {
			lock.lock();
			while (repo.size() <= 0) {
				try {
					condition.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} 
				repo.remove(0);
				condition.signal();
			
		} finally {
			lock.unlock();
		}
	}

	public int size() {
		try {
			lock.lock();
			return repo.size();
		} finally {
			lock.unlock();
		}
	}
}

6. 面向对象设计作业-图书馆管理系统

6.1 系统的功能模块表格,表格中体现出每个模块的负责人。

6.2 运行视频

6.3 讲解自己负责的模块,并粘贴自己负责模块的关键代码(出现学号及姓名)。

系统的基本类及类图

给出关键类截图
代码写的很烂,改进中,希望大家给我一些建议。

public class Entry {
	/**
	 * 职业选择,返回对应的实例变量。
	 * 
	 * @param profession
	 * @return
	 */
	public static User professionJudge(String profession) {
		if (profession.equalsIgnoreCase("Administrator")) {
			Administrator administrator = new Administrator();
			administrator.setAdmit(true);
			return administrator;
		}
		if (profession.equalsIgnoreCase("Student"))
			return new Student();
		if (profession.equalsIgnoreCase("Teacher"))
			return new Teacher();
		else
			return null;

	}

	/**
	 * 填写注册前的基本信息。 返回一个user
	 * 
	 * @param userNo
	 * @param name
	 * @param userId
	 * @param password
	 * @return
	 */
	public static <T extends User> T writePersonalInformation(String profession, Long userNo, String name,
			String userId, String password) {
		User user = professionJudge(profession);
		if (user != null) {
			LoginInformation info = new LoginInformation();
			info.setId(userId);
			info.setPassword(password);
			user.setUserNo(userNo);
			user.setUserName(name);
			user.setLoginInformation(info);
			user.setLibraly(new Library());
			return (T) user;
		}
		return null;

	}

	/**
	 * 将user加入users 只是先将user加入到user仓库
	 * 
	 * @param user
	 * @param set
	 * @return
	 */
	public static <T extends User> boolean register(User user, UserStorage storage) {
		boolean flag = false;
		ObjectInputStream input = null;
		ObjectOutputStream output = null;
		if (user != null) {
			// 先判断user仓库是否有user信息,若没有则去文件中查找
			if (storage.isExit(user.getLoginInformation().getId()) == null) {
				try {
					// 打开文件成功,说明文件存在,不注册
					input = new ObjectInputStream(
							new BufferedInputStream(new FileInputStream(user.getLoginInformation().getId())));
				} catch (FileNotFoundException e) {
					// 打文件开不成功,说明文件不存在那就注册。
					storage.addUser(user);
					flag = true;
					/*
					 * try { output = new ObjectOutputStream( new BufferedOutputStream(new
					 * FileOutputStream(user.getLoginInformation().getId())));
					 * output.writeObject(user); System.out.println("已经注册"); flag = true; } catch
					 * (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) {
					 * e1.printStackTrace(); } finally { try { output.close(); } catch (IOException
					 * e1) { e1.printStackTrace(); } }
					 */
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						if (input != null)
							input.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return flag;

		/*
		 * boolean result = storage.isExit(user.getLoginInformation().getId()); if
		 * (result) { return false; } else { storage.addUser(user); return true; }
		 */

	}

	/**
	 * 登录 直接从文件读取内容
	 * 
	 * @param name
	 * @param password
	 * @param users
	 * @return
	 */

	public static int login(String userId, String password, UserStorage users) {
		ObjectInputStream input = null;
		User user = null;
		int flag = 0;
		if (users.isExit(userId) == null) {
			try {
				input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(userId)));
				try {
					user = (User) input.readObject();
					if (user.getLoginInformation().getPassword().equals(password)) {
						// 登录成功,將user加入Users最后退出系统时自动写入文件
						users.addUser(user);
						flag = 1;
					} else {
						// 帐号密码不匹配
						flag = 0;
					}
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}

			} catch (FileNotFoundException e) {
				// 该帐号没有注册
				flag = -1;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				try {
					if (input != null)
						input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} else {
			user = users.isExit(userId);
			if (password.equals(user.getLoginInformation().getPassword())) {
				flag = 1;
			} else {
				flag = 0;
			}
		}
		return flag;

	}

	/*
	 * boolean result = users.isExit(name); if (result) { int flag = 0;
	 * Iterator<User> iterator = users.getUserSet().iterator(); while
	 * (iterator.hasNext()) { if
	 * (password.equals(iterator.next().getLoginInformation().getPassword())) flag =
	 * 1; // 登录成功 else flag = 0; // 帐号密码不匹配 } return flag;
	 * 
	 * } else { return -1; // 帐号不存在
	 * 
	 * }
	 * 
	 * }
	 */
	/**
	 * 程序开始时恢复书库信息
	 * 
	 * @return
	 */
	public static StackRoom restoreStackRoom() {
		StackRoom stackRoom = null;
		try {
			ObjectInputStream input = new ObjectInputStream(new BufferedInputStream(new FileInputStream("StackRoom")));
			try {
				stackRoom = (StackRoom) input.readObject();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		;
		return stackRoom;

	}
/**
 * 程序结束时使用,更新书库信息
 * 由于用户借书,管理员添加,删除书造成书本数量上的变化
 * @param stackRoom
 */
	public static void saveOrUpdateStackRoom(StackRoom stackRoom) {
		ObjectOutputStream output = null;
		try {
			output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("StackRoom")));
			output.writeObject(stackRoom);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
}
public class Library implements Universal, Serializable {
	private Map<String, BookItem> libraryMap = new TreeMap<>();

	public <T> void print(Collection<T> value) {
		Iterator iterator = value.iterator();
		while (iterator.hasNext())
			System.out.println(iterator.next());

	}

	public void showBooks() {
		Collection<BookItem> BooksItems = libraryMap.values();
		Iterator<BookItem> iterator = BooksItems.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
			;
		}
	}

	private boolean isExit(String bookId) {
		return libraryMap.containsKey(bookId);
	}

	/**
	 * 借书,借书成功书库中该书数量减一
	 * 
	 * @param bookId
	 * @param stackRoom
	 * @return
	 */
	public int borrowBooks(String bookId, StackRoom stackRoom) {
		Collection<Set<BookItem>> setBooksItems = stackRoom.getBooksMap().values();
		Iterator<Set<BookItem>> iterator = setBooksItems.iterator();
		while (iterator.hasNext()) {
			Set<BookItem> setBookItem = iterator.next();
			Iterator setBooks = setBookItem.iterator();
			while (setBooks.hasNext()) {
				BookItem bookItem = (BookItem) setBooks.next();
				Book book = bookItem.getBook();
				if (book.getBookId().equals(bookId)) {
					boolean result = isExit(bookId);
					if (result) {

						BookItem a = libraryMap.get(bookId);
						System.out.println(a);
						if (a.getCount() >= bookItem.getCount()) {
							return 0; // 该书以及全部借出
						} else {
							a.setCount(a.getCount() + 1);
							// 书库的书数量减一
							bookItem.setCount(bookItem.getCount() - 1);
							return 1; // 借书成功
						}
					} else {
						libraryMap.put(bookId, new BookItem(book, 1));
						return 1;
					}
				}
			}

		}
		return -1; // bookId有误,不存在该书

	}

	/**
	 * 还书,还书成功书库中该书数量加一
	 * 
	 * @param bookId
	 * @return
	 */
	public boolean returningBooks(String bookId, StackRoom stackRoom) {
		if (libraryMap.containsKey(bookId)) {
			String category = libraryMap.get(bookId).getBook().getCategory();
			libraryMap.remove(bookId);
			Set<BookItem> bookItems = stackRoom.getBooksMap().get(category);
			for (BookItem bookItem : bookItems) {
				if (bookItem.getBook().getBookId().equals(bookId)) {
					bookItem.setCount(bookItem.getCount() + 1);
					break;
				}
			}
			return true;
		} else {
			return false;
		}

	}

}
public class StackRoom implements Serializable{

	private  Map<String, Set<BookItem>> booksMap = new HashMap<>();

	//已经填入数据,该方法废弃
	/*static {

		Set<BookItem> economicalBook = new HashSet<>();
		economicalBook.add(new BookItem(
				new EconomicalBook("001", "货币金融学", "弗雷德克里S·米什金", "经济", new GregorianCalendar(2001, 6, 1)), 5));
		economicalBook.add(
				new BookItem(new EconomicalBook("002", "博弈论与信息学", "	张维迎", "经济", new GregorianCalendar(2001, 6, 1)), 5));
		economicalBook.add(
				new BookItem(new EconomicalBook("003", "国富论", "亚当.斯密", "经济", new GregorianCalendar(2001, 6, 1)), 5));
		economicalBook.add(new BookItem(
				new EconomicalBook("004", "牛奶可乐经济学", "弗雷德克里S·米什金", "经济", new GregorianCalendar(2001, 6, 1)), 5));
		booksMap.put("经济", economicalBook);

		Set<BookItem> militaryBook = new HashSet<>();
		militaryBook
				.add(new BookItem(new MilitaryBook("005", "孙子兵法", "孙子", "军事", new GregorianCalendar(2001, 6, 1)), 5));
		militaryBook.add(new BookItem(
				new MilitaryBook("006", "第二次世界大战史", "马丁·吉尔伯特 ", "军事", new GregorianCalendar(2001, 6, 1)), 5));
		militaryBook
				.add(new BookItem(new MilitaryBook("007", "太平洋战争", "青梅煮雨", "军事", new GregorianCalendar(2001, 6, 1)), 5));
		militaryBook
				.add(new BookItem(new MilitaryBook("0010", "梦残干戈", "黄朴民", "军事", new GregorianCalendar(2001, 6, 1)), 5));
		booksMap.put("军事", militaryBook);

	}*/
	
	

	/**
	 * 打印
	 * 
	 * @param value
	 */
	public <T> void print(Collection<T> value) {
		if (value == null)
			System.out.println("图书馆无该种类书籍相关信息");
		else {
			Iterator iterator = value.iterator();
			while (iterator.hasNext())
				System.out.println(iterator.next());
		}

	}

	public Map<String, Set<BookItem>> getBooksMap() {
		return booksMap;
	}

	public void setBooksMap(Map<String, Set<BookItem>> booksMap) {
		this.booksMap = booksMap;
	}

	/**
	 * 展示书库,配合搜索使用
	 */
	public void showBooks() {
		Collection<Set<BookItem>> bookItemSet = booksMap.values();
		Iterator<Set<BookItem>> iteratorSet = bookItemSet.iterator();
		while (iteratorSet.hasNext()) {
			print(iteratorSet.next());
		}
	}

	/**
	 * 搜索:依据书的类别
	 * 返回Set,使用print()进行打印
	 * @param key
	 * @return
	 */
	public Set<BookItem> searchBooks(String key) {
		Set<BookItem> bookItems = booksMap.get(key);
		return bookItems;
	}
	

}

7. 选做:使用其他方法解决题目5的生产者消费者问题。

相关资料:来自百度

7.1 使用BlockingQueue解决生产者消费者问题关键代码截图

关键代码

class Repository {// 存放字符串的仓库
	BlockingQueue repo = new LinkedBlockingQueue(10);
	
	public  void add(String t) {
			try {
				repo.put(t);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	}
	public  void remove() {
	try {
		repo.take();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	}
	public int size(){
		return repo.size();
	}
}

7.2 说明为什么不需要显示的使用wait、notify就可以解决同步问题。这样解决相比较wait、notify有什么优点吗?

分析: BlockingQueue顾名思义,阻塞队列。当队列满了的时候进行出队列操作,当队列空了的时候进行入队列操作,我们可以设置阻塞队列的容量,入队操作采用put()方法时,若队列已满则调用此方法的线程被阻断,直到有空间再继续,出队操作采用take()方法时,若队列为空,则阻断进入等待状态直到队列有新的对象被加入为止。

优点:就是我们可以坐享其成,虽然API很强大,但我们也要了解其原理,不能当只会查API的程序员。

7.3 使用Condition解决生产者、消费者问题。

class Repository {// 存放字符串的仓库
	private int capacity = 10;// 仓库容量默认为10
	private List<String> repo = new ArrayList<String>();// repo(仓库),最多只能放10个
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();

	public void add(String t) {
		try {
			lock.lock();
			while(repo.size() >= capacity) {
					try {
						condition.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			} 
				repo.add(t);
				condition.signal();
		
		} finally {
			lock.unlock();}
	}

	public void remove() {
		try {
			lock.lock();
			while (repo.size() <= 0) {
				try {
					condition.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} 
				repo.remove(0);
				condition.signal();
			
		} finally {
			lock.unlock();
		}
	}

	public int size() {
		try {
			lock.lock();
			return repo.size();
		} finally {
			lock.unlock();
		}
	}
}

8. 选做:编写一段代码,证明你会使用ForkJoinPool.

3.码云及PTA

题目集:多线程

3.1. 码云代码提交记录

  • 在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
    必须出现几个要素:提交日期-用户名(姓名与学号)-不提交说明

3.2 截图"多线程"PTA提交列表

  • 需要有两张图(1. 排名图。2.PTA提交列表图)



3.3 统计本周完成的代码量

  • 需要将每周的代码统计情况融合到一张表中

周次 总代码量 新增文件代码量 总文件数 新增文件数
1 665 20 20 20
2 1705 23 23 23
3 1834 30 30 30
4 1073 1073 17 17
5 1073 1073 17 17
6 2207 1134 44 27
7 3292 1085 59 15
8 3505 213 62 3
9 8043 1246 153 16
10 8606 543 167 14
11 9203 597 191 24
12 9203 0 191 0
posted @ 2017-12-04 20:00  Dzwh  阅读(312)  评论(4编辑  收藏  举报