201621123008 《Java程序设计》 第11周学习总结 1. 本周学习总结 2. 书面作业 3.码云及PTA

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

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

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;
	}
}

运行结果

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

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;
	}
}

运行结果

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

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 系统的功能模块表格,表格中体现出每个模块的负责人。

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

6.2 运行视频

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

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

系统的基本类及类图
201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA
201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

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

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历史-设置时间段”, 然后搜索并截图
    必须出现几个要素:提交日期-用户名(姓名与学号)-不提交说明

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

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

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA
201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA
201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

3.3 统计本周完成的代码量

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

201621123008 《Java程序设计》 第11周学习总结
1. 本周学习总结
2. 书面作业
3.码云及PTA

周次 总代码量 新增文件代码量 总文件数 新增文件数
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