本次PTA做业题集多线程
java
Thread.sleep
进行休眠?答:BallRunnable
类实现了Runnable
接口,支持了多线程,在其中用于给线程指派任务,在类中的run方法里经过循环调用小球的移动函数move
和重画函数repaint
来实现小球的移动轨迹。还有用了Treep.sleep()
来使线程休眠一段时间。
使用Tread.sleep
让线程进行休眠是为了延缓线程完成的时间,这样可让咱们看到小球的移动,否则不进行休眠的话,这个程序会在一个很快的时间内完成,没有办法看到小球的移动轨迹,而且sleep()为Thread类的静态方法,调用它不会建立一个新线程。安全
答:Ball.java
完成的两件事:多线程
move
函数实现小球的移动方法getShape
函数来获取小球的大小和坐标BallComponent
对象也实现了两件事:dom
其内部的ArrayList用于存放添加的小球
程序中只生成了一个BallComponent对象
经过源代码能够看出每按一次start
按钮,addBall
方法都会启动一个新线程,所以每一个小球都是在本身的线程中绘制的。eclipse
答:可使用Math.random()方法将ball.java
中的x
、y
、dx
、dy
的值设置成随机数来达到每次点击start
时使小球以不一样位置出发和以不一样步前进。
函数
并回答:a)经过定义Runnable
接口的实现类来实现多线程程序比经过继承自Thread
类实现多线程程序有何好处?b) 6-1,6-3,6-11实验总结。
答:(a).使用实现Runnable
接口来实现多继承的程序的好处:性能
Runnable
接口适合于资源的共享,以下两张图片:
能够看出,虽然两个程序中都建立了两个线程,可是使用Runnable
实现多线程使两个线程一块儿完成两个任务,达到资源共享的目的。
(b).Thread实验总结
这题中要注意MyThread类有一个有参构造函数,用于接收循环次数,而后要将标识信息放在for循环外,其余就是普通的打印输出了。
Runnable实验总结
这题使用了匿名内部类来实现Runnable接口的run方法来完成程序。获取当前的线程名字要用Thread.currentThread().getName()
,而后就是按要求输出就OK了。
PrintTask实验总结
这题……除了类名和最后输出的标识信息,其余都和6-1同样hhhh学习
Thread t1 = new Thread(() -> { System.out.println(mainThreadName); System.out.println(Thread.currentThread().getName()); System.out.println(Arrays.toString(Thread.class.getInterfaces())); });
答:在Java的Thread类中提供了一个stop()方法用来终止线程,不过,由于这个方法会将执行到一半的线程强行终止,,不能保证线程的资源正确释放,因此已经被废弃了。
如今在咱们须要中止一个线程的时候通常使用一个boolean类型的变量来终止线程,这样可使用while语句,在运行中经过改变boolean标记值来使while循环退出来达到中止线程的做用。
咱们还可使用interrupt
方法来终止线程,可是,这种方法并不适用于一个正在运行的线程,它是用于中止一个受到阻塞的线程,经过使受阻塞的线程抛出异常来退出阻塞的状态。
所以仍是使用boolean类型的变量来终止线程的方法比较好。测试
这题就是跟着注释一步步写下来就能够了。
CountDownLatch
类是一个同步计数器,构造时传入int参数,用于表示任务的个数。这个参数是计数器的初始值。
使用Executors
类的newFixedThreadPool
方法能够建立一个固定线程数的线程池。线程
要想让ArrayList等达到线程安全,只须要用synchronizedList
修饰list便可。synchronizedList
经过对部分操做加上synchronized
来保证线程安全。
其实只要在Counter类的对id进行操做的两个方法前加上synchronized
关键字就能够了,它能够经过给共享资源上一道锁来使在同一个时间内只容许一个线程访问共享资源,以此来实现同步机制。
完成题集6-4(互斥访问)与6-5(同步访问)
答:还能够经过synchronized
的同步代码块来实现互斥访问。
修改后的方法以下:
答:同步方法直接在方法名前面加synchonrized
关键字来实现对对象的加锁,而同步代码块则是在方法的内部使用synchonrized
关键字来加锁,所以,同步方法的做用范围比同步代码块大,其性能则不如同步代码块。
答:实现互斥访的原理是程序经过给共享资源上一道锁,让给定时间内只容许一个线程来访问共享资源。
下面经过分析一个从书上看到的模拟火车站售票系统的程序来讲明同步机制运行时的线程状态,代码以下
public class ThreadSafeTest implements Runnable { int num = 10; //设置当前总票数 public void run() { while (true) { synchronized ("") { if (num > 0) { try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } System.out.println("tickets" + --num); } } } } public static void main(String[] args) { ThreadSafeTest t = new ThreadSafeTest(); //实例化类对象 Thread tA = new Thread(t); // 以该类对象分别实例化4个线程 Thread tB = new Thread(t); Thread tC = new Thread(t); Thread tD = new Thread(t); tA.start(); // 分别启动进程 tB.start(); tC.start(); tD.start(); } }
当咱们运行程序的时候,一个线程先开始工做,给num上了一把锁,而后其余三个线程就不能再访问这个区域,等到tA执行完售票的操做将票数减1并输出后,对象锁被释放,而后下一个线程又开始工做,再给num上了一把锁,以此类推,直到票数为0后结束进程。
能够看出运行结果不正常,最后还有出现货物有剩余的状况,这是由于Producer和customer的存取速度不同,致使二者不能很好的进行交互,从而使最后剩于货物结果出现异常。
synchronized, wait, notify
解决该问题(关键代码截图,需出现学号)
运行结果:
运行结果:
学生 | 负责任务 |
---|---|
陈晓菲 | 图书管理模块 |
廖文姑 | 菜单类及测试类 |
贾海涛 | 用户管理模块 |
我负责的是图书管理模块,里面包含两个类,图书馆类和图书类,用于进行书籍的管理。
图书类:
//201621123031 public class Book { private String name; private long ID; private String category; public Book(String name,long ID,String category){ ………… } /* *get()和set()和方法 */
图书馆类:
public class Library { public enum LendOrBack{ //用于变动借书还书后的书籍变化 LEND,BACK } private static Map<Book,Integer> books=new TreeMap<Book,Integer>(); //用于存储图书信息及数量 static{ initializeBookStore(); } private static void initializeBookStore(){ Book book1 = new Book("红与黑",111,"文学类"); Book book2 = new Book("平凡的世界",112,"文学类"); Book book3 = new Book("双城记",113,"文学类"); Book book4 = new Book("资本论",114,"经济类"); Book book5 = new Book("孙子兵法",115,"军事类"); Book book6 = new Book("人间词话",116,"艺术类"); Book book7 = new Book("诗经",117,"艺术类"); Book book8 = new Book("楚辞",118,"艺术类"); Book book9 = new Book("战国策",119,"历史类"); Book book10 = new Book("国家地理",120,"地理类"); books.put(book1, 30); books.put(book2, 50); books.put(book3, 40); books.put(book4, 10); books.put(book5, 20); books.put(book6, 15); books.put(book7, 35); books.put(book8, 40); books.put(book9, 5); books.put(book10, 10); } public static Book peekBook(long ID) { //根据ID获取某本书籍的信息 Iterator<Map.Entry<Book, Integer>> m = books.entrySet().iterator(); while(m.hasNext()){ Map.Entry<Book, Integer> e = m.next(); if(e.getKey().getID()==ID&&e.getValue()>0) return e.getKey(); } return null; } public static ArrayList<Book> peekBooks(String name) { //根据书名获取某本书籍的信息 ……………… } public static void add(Book book,int num){ //添加书籍 if(books.get(book)==null){ books.put(book, num); } else{ books.put(book, books.get(book)+num); } } public static void remove(Book book){ //移除书籍 books.remove(book); } public static void lendOrBack(Book book,LendOrBack action){ //进行借书还书操做时书籍数量的变动 switch(action) { case LEND:{ books.put(book, books.get(book)-1); break; } case BACK:{ books.put(book, books.get(book)+1); break; } } } public static void display(){ //展现图书馆的藏书 Iterator<Map.Entry<Book, Integer>> m = books.entrySet().iterator(); System.out.println(" 书名 \t\t\tID\t\t类别\t\t数量"); while(m.hasNext()){ Map.Entry<Book, Integer> e = m.next(); if(e.getValue()>0) System.out.println(e.getKey().toString()+"\t\t"+e.getValue()); } System.out.println(); } }
BlockingQueue
解决生产者消费者问题关键代码截图
答:BlockingQueue
是阻塞队列,当队列中没有数据的状况下,消费者线程会被自动阻塞,直到有数据进入队列,而当队列中填满数据的时候,生产者的全部线程都会被自动阻塞,直到队列中有空的位置,线程才会被自动唤醒。所以它不须要使用wait、notify就能够达到解决同步问题的方法,这样的方法比wait、notify更简单且更方便。
题目集:多线程
须要有两张图(1. 排名图。2.PTA提交列表图)
须要将每周的代码统计状况融合到一张表中。
周次 | 总代码量 | 新增代码量 | 总文件数 | 新增文件数 |
---|---|---|---|---|
2 | 607 | 607 | 15 | 15 |
3 | 1642 | 1035 | 33 | 18 |
5 | 2044 | 402 | 42 | 9 |
6 | 2874 | 830 | 57 | 15 |
7 | 3161 | 287 | 63 | 6 |
8 | 4299 | 1138 | 72 | 9 |
9 | 4831 | 532 | 81 | 9 |
10 | 5475 | 644 | 93 | 12 |
11 | 5958 | 483 | 102 | 9 |
12 | 6819 | 861 | 116 | 14 |
观看相关调试视频
使用eclipse调试的步骤:
F5:单步执行程序,遇到方法时进入。在碰到方法内部出现问题的时候,就要用F5去深刻方法内部来进行调试。
F6:单步执行程序,遇到方法时跳过。在不用理会深层操做的时候使用F6。
F7:单步执行程序,从当前方法跳出。当进入某个方法内部想跳出来时使用F7。