201621123061《Java课程设计》第11次学习总结
1. 本周学习总结
1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容。
- 1.创建线程有两个方法,但我们一般只用中一个,即定义实现Runnable接口的类,实现它的run()方法,,然后将这个类的实例作为Thread构造方法的参数。
- 2.Runnable是任务,只有Thread是线程。必须将实现Runnable的类的对象放入Thread中,才能在线程中运行。
- 3.多线程的冲突可以用使用synchronized标记方法和标记代码块。
- 4.volatile用来修饰变量,就会让变量之间具有可见性。
2. 书面作业
本次PTA作业题集多线程
1. 源代码阅读:多线程程序BounceThread
1.1 BallRunnable类有什么用?为什么代码中需要调用Thread.sleep进行休眠?
BallRunnable类实现了Runnable接口,重写了Run方法,支持多线程指派任务,使用Thread.sleep进行休眠是为了让我们看清楚小球移动的轨迹,否则速度太快看不清楚。
1.2 Ball.java只做了两件事,这两件事分别是什么?BallComponent对象是干什么的?其内部的ArrayList有什么用?程序运行过程中,生成了几个BallComponent对象?该程序使用了多线程技术,每个小球是分别在不同的线程中进行绘制吗?
- 定义了两个方法:分别是move()实现小球移动。getShape()获取坐标和大小。
- 定义两个方法:分别是add()添加球球,和paintComponent()打印球球。ArrayList用来存放小球。
- 运行过程,生成一个BallComponent对象。
- 是。
1.3 选做:程序改写:程序运行时,每个小球都是从固定位置出发。如何改写该程序,使得当点击start时,每个小球可以从不同位置出发、以不同的步进移动?
每个小球可以从不同位置出发,也就是随机出发,那就使用Math.random().
private double x = Math.random()*50;
private double y = Math.random()*50;
private double dx = Math.random()*5;
private double dy = Math.random()*5;
1.4 选做:不同小球的移动轨迹一模一样。改造程序,使得每个小球运行轨迹不完全一样,比如有的可以走余弦轨迹、有的可以走方波轨迹、有的走布朗运动、有的走五角星,等等。
2. 实验总结:题集(多线程)
2.1 题目:Thread、PrintTask、Runnable与匿名内部类。
并回答:a)通过定义Runnable接口的实现类来实现多线程程序比通过继承自Thread类实现多线程程序有何好处?b) 6-1,6-3,6-11实验总结。
- a).Java不能多继承,但是可以实现多个接口。
- b).6-1 MyThread继承Thread,要重写run()。6-3.用Thread.currentThread().getName()可以获取当前的线程名字。6-11.这一题和6-1 Thread差不多,只不过一个是继承类,一个是实现接口。
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与停止线程)。回答:需要怎样才能正确地停止一个运行中的线程?
要对word判空,刚开始做的·时候没有判空会抛出空指针的异常。
在while循环时加个flag控制跳出循环,不要用stop不安全。
2.4 选做:6-8(CountDownLatch)实验总结
使用Executors类的newFixedThreadPool()方法创建一个线程池。
2.5 选做:6-9(集合同步问题)实验总结
用synchronizedList修饰list。
2.6 选做:较难:6-10(Callable),并回答为什么有Runnable了还需要Callable?实验总结。
3. 互斥访问
3.1 修改TestUnSynchronizedThread.java源代码使其可以同步访问。(关键代码截图,需出现学号)


3.2 选做:进一步使用执行器改进相应代码(关键代码截图,需出现学号)
4. 互斥访问与同步访问
完成题集6-4(互斥访问)与6-5(同步访问)
4.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法可以使用synchronized实现互斥同步访问,使用代码说明(请出现相关代码及学号)?
使用lock,unlock。
\\陈锦霞201621123061
public void deposit(int money) {
lock.lock();
try {
this.balance += money;
condition.signal();
} finally {
lock.unlock();
}
}
public void withdraw(int money) {
lock.lock();
try {
while (this.balance - money < 0) {
try {
wait();
} catch (InterruptedException e) {
}
}
this.balance -= money;
condition.signal();
} finally {
lock.unlock();
}
}
4.2 同步代码块与同步方法有何区别?
使用synchronized关键字修饰的方法叫同步方法,此时内置锁会保护整个方法。锁的范围比较大。
使用synchronized关键字修饰的语句块叫同步代码块。被该关键字修饰的语句块会自动被加上内置锁,锁的范围比较小,性能较好。
4.3 实现互斥访问的原理是什么?请使用对象锁概念并结合相应的代码块进行说明。当程序执行synchronized同步代码块或者同步方法时,线程的状态是怎么变化的?
- 通过获得唯一的锁来打开资源,其他线程就先等待,notify()之后进入Lock Pool,使用资源之后,就把锁还回去。
![]()
th1获得id锁,读取值,th2等待,th1的id+1,将值传给id,锁被释放。th2获得锁,重复th1的步骤。
线程变化:多个线程进行争夺对象锁,一个线程获得对象锁,其余等待该线程结束。
4.4 Java多线程中使用什么关键字实现线程之间的通信,进而实现线程的协同工作?
wait()和notify()。
5. 线程间的合作:生产者消费者问题
5.1 运行MyProducerConsumerTest.java。正常运行结果应该是仓库还剩0个货物。多运行几次,观察结果,并回答:结果正常吗?哪里不正常?为什么?
- 不正常。每次结果都是不确定的。Comsumor和Producer的速度不一样,同时进行存取操作。冲突了。
5.2 使用synchronized, wait, notify解决该问题(关键代码截图,需出现学号)
//陈锦霞201621123061
class Repository {// 存放字符串的仓库
private int capacity = 10;//仓库容量默认为10
private List<String> repo = new ArrayList<String>();// repo(仓库),最多只能放10个
public synchronized void add(String t) {
while(repo.size() >= capacity) {
System.out.println("仓库已满!无法添加货物。");
try{
wait();
}catch(Exception e){
e.printStackTrace();
}
}
repo.add(t);
System.out.println("已添加!");
notify();
}
public synchronized void remove() {
while(repo.size() <= 0) {
System.out.println("仓库无货!无法从仓库取货");
try{
wait();
}catch(Exception e){
e.printStackTrace();
}
}
repo.remove(0);
System.out.println("已取走!");
notify();
}
5.3 选做:使用Lock与Condition对象解决该问题。
//陈锦霞201621123061
class Repository {// 存放字符串的仓库
private int capacity = 10;//仓库容量默认为10
private List<String> repo = new ArrayList<String>();// repo(仓库),最多只能放10个
public synchronized void add(String t) {
lock.lock();
while(repo.size() >= capacity) {
System.out.println("仓库已满!无法添加货物。");
try{
condition.await();
}catch(Exception e){
e.printStackTrace();
}
}
repo.add(t);
System.out.println("已添加!");
condition.signal();
lock.unlock();
}
public synchronized void remove() {
lock.lock();
while(repo.size() <= 0) {
System.out.println("仓库无货!无法从仓库取货");
try{
condition.await();
}catch(Exception e){
e.printStackTrace();
}
}
repo.remove(0);
System.out.println("已取走!");
condition.signal();
lock.unlock();
}
6. 面向对象设计作业-图书馆管理系统
6.1 系统的功能模块表格,表格中体现出每个模块的负责人。
我自己
6.2 运行视频
没有做出来,主要是时间太短,自己基础也并不好,模仿资料写的。
6.3 讲解自己负责的模块,并粘贴自己负责模块的关键代码(出现学号及姓名)。
只有一小部分代码
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
public class Login extends JFrame{
//声明标签、按钮、文本框和密码框
private JLabel JLb1;
private JLabel JLb2;
private JButton Ok_btn;
private JButton Cancel_btn;
private JTextField jtflduser;
private JPasswordField jtpwdfld;
//声明窗口
private JFrame frame;
//构造方法
public Login(){
frame=new JFrame("登录");
Container content=frame.getContentPane();
//采用GridLayout布局管理器
content.setLayout(new GridLayout(3,2,20,20));
JLb1=new JLabel("用户名");
JLb2=new JLabel("密 码");
//将标签置于居中位置
JLb1.setHorizontalAlignment(SwingConstants.CENTER);
JLb2.setHorizontalAlignment(SwingConstants.CENTER);
jtflduser=new JTextField();
jtpwdfld=new JPasswordField();
Ok_btn=new JButton("确定");
Cancel_btn=new JButton("取消");
//为按钮增加事件监听者
Ok_btn.addActionListener(new ActionHandler());
Cancel_btn.addActionListener(new ActionHandler());
//添加标签、文本框和密码框到窗口
content.add(JLb1);
content.add(jtflduser);
content.add(JLb2);
content.add(jtpwdfld);
content.add(Ok_btn);
content.add(Cancel_btn);
frame.pack();
//设定登录窗口启动时出现在屏幕中央位置
frame.setLocationRelativeTo(null);
frame.setSize(300,200);
frame.setVisible(true);
}//Login() method
/**
*实现ActionListener监听,激活组件响应
*/
class ActionHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
String str1,str2,sqlStr;
Object obj=e.getSource();
//获得文本框和密码框的数据
str1=jtflduser.getText().trim();
str2=new String(jtpwdfld.getPassword()).trim();
try{
//点击确定按钮
if(obj.equals(Ok_btn)){
if(str1.equals("")){
JOptionPane.showMessageDialog(frame,"用户名不能为空!");
return;
}
if(result.next()){
//弹出对话框提示登录成功
JOptionPane.showMessageDialog(frame,"登录成功!");
//打开图书管理主页面
bookmain bookmain1=new bookmain();
bookmain1.go();
//关闭登录窗口
frame.dispose();
}else{ JOptionPane.showMessageDialog(frame,"用户名或密码错误");
}
}else if(obj.equals(Cancel_btn)){
//点击取消按钮
System.exit(0);
}
}catch(ClassNotFoundException ce){
//捕获异常
System.out.println("SQLException:"+ce.getMessage());
}
catch(SQLException ex){
//捕获异常
System.out.println(ex);
}
catch (Exception s) {
//捕获异常
s.printStackTrace();
}
}
}
public static void main(String args[]){
Login login=new Login();
}//main
}//class ActionHandler
这是用户界面
3.码云及PTA
题目集:多线程
3.1. 码云代码提交记录
在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
必须出现几个要素:提交日期-用户名(姓名与学号)-不提交说明

3.2 截图"多线程"PTA提交列表
需要有两张图(1. 排名图。2.PTA提交列表图)


3.3 统计本周完成的代码量
需要将每周的代码统计情况融合到一张表中。

| 周次 | 行数 | 新增行数 | 文件数 | 新增文件数 |
|---|---|---|---|---|
| 1 | 91 | 91 | 5 | 5 |
| 2 | 504 | 413 | 18 | 13 |
| 3 | 1092 | 588 | 28 | 10 |
| 5 | 1158 | 129 | 34 | 6 |
| 6 | 1539 | 381 | 40 | 6 |
| 7 | 2023 | 484 | 49 | 9 |
| 8 | 2477 | 454 | 57 | 8 |
| 9 | 2709 | 232 | 63 | 6 |
| 10 | 3156 | 447 | 70 | 7 |
| 11 | 3531 | 375 | 79 | 9 |
| 12 | 4083 | 552 | 91 | 12 |

浙公网安备 33010602011771号