1. 本周学习总结

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

2. 书面作业

本次PTA作业题集多线程

**1.互斥访问与同步访问 **

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

**1.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法实现互斥同步访问(请出现相关代码)? **

  • 可以使用synchronized代码块
public static void addId() {
synchronized (Counter.class) {//代表Counter类型的对象
id++;
}
}
  • 还可以使用Lock与Condition对象方法
public class Bank
{
public Bank(int n, double initialBalance)
{
accounts = new double[n];
for (int i = 0; i < accounts.length; i++)
accounts[i] = initialBalance;
bankLock = new ReentrantLock();
sufficientFunds = bankLock.newCondition();
} public void transfer(int from, int to, double amount) throws InterruptedException
{
bankLock.lock();
try
{
while (accounts[from] < amount)
sufficientFunds.await();
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
sufficientFunds.signalAll();
}
finally
{
bankLock.unlock();
}
} public double getTotalBalance()
{
bankLock.lock();
try
{
double sum = 0; for (double a : accounts)
sum += a; return sum;
}
finally
{
bankLock.unlock();
}
} public int size()
{
return accounts.length;
} private final double[] accounts;
private Lock bankLock;
private Condition sufficientFunds;
}

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

区别在于:

  • 同步方法直接在方法上使用synchronized修饰,实现加锁;而同步代码块则在方法内部使用synchronized代码块,实现加锁。
  • 在所加的锁的作用范围来说,同步方法的范围比较大,而同步代码块的范围会更小一些。
  • 对比两个的性能来说,同步代码块的性能更好些。因为一般同步的范围越大,性能就越差,而同步方法的范围比同步代码块的范围要大。

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

class MyCounter{
private int i = 0;
public void increment(){
//i++;
synchronized (this) {
i++;
}
}
……
}
  • 实现互斥访问的原理是:在程序中,每个对象都有一把锁,只有获得了对象锁,才能执行相应的synchronized代码块或者方法。

    例如:在上述的代码段中,可以获得对象“this”上的内部锁。当执行程序时,如果不能获得相对应的对象锁,那么将不能执行上述代码块中的内容,即synchronized同步代码块中的i++语句,就必须等待,等待获得对象锁。从而通过对象锁实现了互斥访问。
  • 线程的状态的变化为:如果没有获得对象锁就进入Look Pool状态,等待同步锁被释放;同步锁释放后,线程进入Runnable状态。

**1.4 Java多线程中使用什么关键字实现线程之间的通信,进而实现线程的协同工作?为什么同步访问一般都要放到synchronized方法或者代码块中? **

  • Java多线程中使用wait()和notify()/notifyAll()方法来实现线程之间的通信,进而实现线程的协同工作。
  • 因为wait()方法和notify()/notifyAll()方法都只能在被声明为synchronized的方法或代码段中调用。

**2.交替执行 **

**实验总结(不管有没有做出来) **

本题是要我们写入一串字符串,然后在构造函数中将字符串以空格为分隔写入另一个字符数组作为任务,并且任务完成后要将任务删除,则相应的需要将任务数减去已经执行的任务数量。因为题目要求两个线程是交替执行的,所以我们需要判断当前的任务是应该由谁来进行执行的。可以使用flag来进行判断,当flag==true时由线程1执行,输出结果并将flag赋值为false和使用notify()唤醒其他线程。当flag==false时,同理。

**3.互斥访问 **

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

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

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

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

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

  • 结果不正常。
  • 有时候仓库剩余的货物个数不为0个。
  • 因为该程序使用的是多线程,而多线程除了互斥问题外,还有同步问题。在本题的程序代码中,使用了synchronized方法,实现了互斥访问,但是并没有对两个相互相交线程之间的运行进度进行协调,导致有可能出现货装进仓库太多了,来不及取的情况。

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

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

**5.查询资料回答:什么是线程安全?(用自己的话与代码总结,写自己看的懂的作业) **

  • 线程安全就是如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码,但是实际上代码每次的运行结果和在单线程时运行的结果是一样的,而且其他的变量的值也和预期的是一样的。
  • 例如:两个线程a、b同时执行如下语句,假设id的初值为2
public static void addId() {
id++;
}
  1. 运行时,a线程读取i的值为2,并将2++得到3,这时候还未来得及将3写回id
  2. 这时候b读取id的值还为2,并将2++得到3,
  3. 然后a,b依次把他们的值(3)写回id,那么id最终值为3而不是4

    所以,我们需要用到synchronized关键字,在addId方法前加上synchronized声明,将线程不安全转变为线程安全。
public static synchronized void addId() {
id++;
}

**6.选做:实验总结 **

**6.1 4-8(CountDownLatch)实验总结 **

CountDownLatch是一个同步工具类,它的作用主要是使线程等待,等待其他线程完成后再执行。程序中我们建立CountDownLatch对象,且程序中的线程数为poolSize,所以我们要写入调用次数poolSize。使用for循环时,应注意判断条件不为任务数n,应为线程数poolSize,且因为MyTask类的构造函数为public MyTask(CountDownLatch latch),所以我们将子线程加进线程池执行时MyTask的“()”中为CountDownLatch的变量名latch。

**6.2 4-9(集合同步问题)实验总结 **

因为List不是线程安全的,所以我们需要将其转化,获得同步集合。一般来说,我们可以使用Collections工具类提供的synchronizedCollection方法来获得同步集合。即在本题中我们只需要使用synchronizedList方法就可以了。

**6.3 较难:4-10(Callable),并回答为什么有Runnable了还需要Callable?实验总结。 **

  • 因为在Runnable接口中的public void run()方法是无返回值的,如果我们希望线程运算后将结果返回,这时候使用Runnable是不能够实现我们的需求的。所以这时候我们就需要使用到Callable了。Callable代表有返回值的任务,能够将我们需要的结果返回。
  • 实验总结:CalculateTask类实现了Callable接口,且希望返回n的斐波那契值数值,所以我们需要使用Callable<Integer>和Callable接口的call()方法来返回所需的结果。因为输入的n是为个数,所以我们需要在call()方法中编写输出斐波那契值数值的代码。然后在main函数中使用到了线程池,List列表和Future接口,运行任务后,将计算结果写入List列表中,再遍历求和,最后要记得使用exec.shutdown();来拒绝任务继续输入。

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

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

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

  • 因为BlockingQueue是线程安全的队列类,是阻塞队列。常用的队列主要分为两中:先进先出和后进先出,每个时刻只允许一个任务插入或者删除,保证了线程安全。并且队列会在队空和队满的情况下,自动阻塞,在队满后有空位出现时,线程会被自动唤醒。所以不需要显示的使用wait、notify就可以解决同步问题。
  • 相比之下,比wait、notify更加简单,方便。因为当我们使用了BlockingQueue就再也不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程了,这一切BlockingQueue都可以自动完成。

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

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

package keke;

import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask; class Task extends RecursiveTask<Integer>{
private int n;
public Task(int num) {
this.n=num;
}
@Override
protected Integer compute() {
if(n==100){
return n*n;
}
Task newtask=new Task(n+1);
newtask.fork();
return n*n+newtask.join();
} }
public class Mainboke08 {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
System.out.println("输入数字num(num<=100):");
int num=in.nextInt();
if(num<100)
System.out.println("计算从"+num+"*"+num+"+...+100*100:");
else if(num>100){
System.out.println("输入的数>100了,请重新输入!");
num=in.nextInt();
}
else
System.out.println("计算"+num+"*"+num+":");
Task task=new Task(num);
ForkJoinPool forkJoinPool = new ForkJoinPool();
Future<Integer> result = forkJoinPool.submit(task);
try {
System.out.println("结果为:"+result.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
forkJoinPool.shutdown();
}
}

3. 码云上代码提交记录

题目集:多线程(4-4到4-10)

**3.1. 码云代码提交记录 **

在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图

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

4.选做:课外阅读

**4.1 Questions and Exercises: Concurrency,学习总结。 **

**4.2 Java多线程之Executor、ExecutorService、Executors、Callable、Future与FutureTask **

**4.3 线程池,这一篇或许就够了 **

**4.4 Java 8 Concurrency Tutorial: Threads and Executors **

201521123006 《java程序设计》 第11周学习总结的更多相关文章

  1. 201521123045 <java程序设计>第11周学习总结

    201521123045 <java程序设计>第11周学习总结 1. 本周学习总结 2. 书面作业 2. 书面作业 Q1.1.互斥访问与同步访问完成题集4-4(互斥访问)与4-5(同步访问 ...

  2. 201521123027 <java程序设计>第11周学习总结

    1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2.书面作业 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchro ...

  3. 2018面向对象程序设计(Java)第11周学习指导及要求

    2018面向对象程序设计(Java)第11周学习指导及要求 (2018.11.8-2018.11.11)   学习目标 (1) 掌握Vetor.Stack.Hashtable三个类的用途及常用API: ...

  4. 面向对象程序设计(JAVA) 第11周学习指导及要求

    2019面向对象程序设计(Java)第11周学习指导及要求 (2019.11.8-2018.11.11)   学习目标 理解泛型概念: 掌握泛型类的定义与使用: 掌握泛型方法的声明与使用: 掌握泛型接 ...

  5. 20145236 《Java程序设计》第九周学习总结

    20145236 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API ...

  6. 2018-2019 2 20175230《Java程序设计》第九周学习总结

    <Java程序设计>第九周学习总结 主要内容 MySQL数据库管理系统 1.下载 2.安装 启动MySQL数据库服务器 1.启动 2.root用户 MySQL客户端管理工具 建立连接 建立 ...

  7. 20175209 《Java程序设计》第九周学习总结

    20175209 <Java程序设计>第九周学习总结 一.教材知识点总结 有关数据库下载中存在可能出现的问题已经在博客<数据库安装和使用过程中出现的一些问题>给出了相应的解决办 ...

  8. 20175208 《Java程序设计》第九周学习总结

    20175208 2018-2019-2 <Java程序设计>第九周学习总结 一.教材学习内容总结: 第11章 JDBC与MySQL数据库 MySQL数据库管理系统 MySQL数据库管理系 ...

  9. 20175202 《Java程序设计》第九周学习总结

    20175202 2018-2019-2 <Java程序设计>第九周学习总结 教材知识点总结 第11章 JDBC与MySQL数据库 MySQL数据库管理系统 MySQL数据库管理系统,简称 ...

  10. 20175227张雪莹 2018-2019-2 《Java程序设计》第九周学习总结

    20175227张雪莹 2018-2019-2 <Java程序设计>第九周学习总结 教材学习内容总结 第十一章 JDBC数据库操作 MySQL数据库管理系统 下载安装MySQL 若下载的是 ...

随机推荐

  1. 进程通信-SendMessage使用方法

    进程通信-SendMessage的使用方法 用过SendMessage进行进程通信的同学都知道,这个函数一般都搭配FindWindow使用.通过FindWindow查找进程句柄,然后使用SendMes ...

  2. CSS选择器 - 性能的探究及提升

    [本博客为原创:http://www.cnblogs.com/HeavenBin/]  前言: 在工作中编写CSS样式表时随着选择器层数的增加总会看到选择器又丑又长的情况,利用工作之余研究从其命名再到 ...

  3. 如何在GitHub上生成ssh公钥并用NetBeans克隆项目

    一.生成ssh公钥. 1.首先判断本机是否创建了公有密钥: $ ls ~/.ssh 这个命令用于检查是否已经存在 id_rsa.pub 或 id_dsa.pub 文件,如果文件已经存在,下面步骤可省略 ...

  4. .net 正则获取url参数

    public static string GetParams(string paramName) { var url = "http://fdsfs.com/Home/Index?corp= ...

  5. CSS选择器大汇总

    CSS选择器是学习CSS以及Web编程的基础. 整理出常用的CSS选择器,供自己和大家一起学习. 基本选择器 * /*通用元素选择器,匹配页面任何元素(这也就决定了我们很少使用)*/ #id /*id ...

  6. 在Debian9(linux)上使用 的 python 3 IDLE(已经安装了python 2.7 的情况下)

    在Debian9(Stable)中默认安装了python2.7和pytohon3.5两个版本,但是没有IDLE,本人想用pytihon3.5的IDLE,将本次解决问题在此Mark一下, 首先,执行 s ...

  7. 【Linux】CentOS7无法使用tab补全功能

    公司新项目在云环境上用CentOS7搭服务器的时候,遇见了无法Tab键自动补齐的情况,上网搜了一下,是因为Centos7在使用最小化安装的时候,没有安装自动补全的包,需要自己手动安装. yum ins ...

  8. 《Java从入门到放弃》JavaSE入门篇:面向对象概念(入门版)

    要知道什么是面向对象,你首先要有个对象吧,所以······没有对象的可以回家洗洗睡了· 好吧,前面是开玩笑,要说明什么是面向对象,我们还是先 例子: 小呆:"小傻,你今天早餐吃的什么?&qu ...

  9. 如何使用 flannel host-gw backend?- 每天5分钟玩转 Docker 容器技术(62)

    flannel 支持多种 backend,前面我们讨论的是 vxlan,host-gw 是 flannel 的另一个 backend,本节会将前面的 vxlan backend 切换成 host-gw ...

  10. web中转发、重定向等问题的路径

    web中常用路径,转发,重定向,form表单action的路径 路径的写法: a.绝对路径写法:ServeltContext都必须用绝对路径."/" b.相对路径:其他情况都可以使 ...