201521123013 《Java程序设计》第11周学习总结
1. 本章学习总结
2. 书面作业
Q1.1.互斥访问与同步访问
完成题集4-4(互斥访问)与4-5(同步访问)
1.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法实现互斥同步访问(请出现相关代码)?
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
synchronized void deposit(int money){
lock.lock();
try{
balance+=money;
condition.signal();
}finally {
lock.unlock();
}
}
synchronized void withdraw(int money){
lock.lock();
try{
while(balance<money){
try{
condition.await();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
balance-=money;
}finally {
lock.unlock();
}
}
1.2 同步代码块与同步方法有何区别?
- 同步方法是直接在方法上加synchronized实现加锁,而同步代码块则是在方法内部通过
synchronized(this){}
实现加锁。因为同步方法锁的范围比较大,一般同步范围越大性能越差,如果只是让某些个线程不能同时访问方法内部的部分代码的话,应该采取同步代码,这样访问对象的时间性能就会比较好。 - 举个例子
public synchronized void test1() {
System.out.println("hello");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void test2() {
synchronized(this) {
System.out.println("hello world");
}
}
//hello world隔了五秒才运行,从这段代码可以看出如果将synchronized放在方法上,同步锁的范围是整个方法,所以test2想要获得对象锁必须等test1的方法全部执行完,也就是需要在休眠五秒后才能得到锁。
1.3 实现互斥访问的原理是什么?请使用对象锁概念并结合相应的代码块进行说明。当程序执行synchronized同步代码块或者同步方法时,线程的状态是怎么变化的?
- 每个对象都有一把锁,只有获得this对象上的内部锁,才可以访问该段资源,没有获得对象锁的线程在Lock Pool中,等待获得对象锁的线程运行完解锁,然后通过竞争获得对象锁再运行。也就是一段时间内只允许一个线程访问这段共享资源。
class Counter {
private static int id = 0;
//当有线程1先对其调用addId方法,另一线程2调用subtractId方法,
public static synchronized void addId() {
id++; //线程1获得对象锁(线程2锁池中等待获得锁)对其id++,执行完后,释放this上的对象锁,
}
public static synchronized void subtractId() {
id--; //另一线程2获得对象锁,对其id--,然后释放对象锁。
}
public static int getId() {
return id;
}
}
- 多个线程start(),竞争对象锁,某一线程竞争获得对象锁,其余线程在等待池中等待线程释放对象锁,当线程释放对象锁其余线程又开始竞争对象锁,直到程序结束。
1.4 Java多线程中使用什么关键字实现线程之间的通信,进而实现线程的协同工作?为什么同步访问一般都要放到synchronized方法或者代码块中?
- 使用wait ()、notify()、notifyAll()实现线程之间的通信
- 因为将共享资源放在synchronized方法或者代码块中就可以保证获得对象锁的线程可以在对共享资源进行操作的时候不被打扰,其他线程只能在其之后才能访问,避免了多个线程访问同一资源引起的冲突。
Q2.交替执行
2.1 实验总结
public synchronized void jiaoti1(){
while(getSize()>0){
if(flag){
try{
wait();
}catch (Exception e) {
// TODO: handle exception
}
}
else {
System.out.println(Thread.currentThread().getName()+" finish "+str[i]);
i++;
flag=true;
notify();
}
}
}
...
- 因为两线程交替执行所以需要wait()、notify()的协作。设置flag初始值为flase,执行了Woker1,置flag为true,唤醒Woker2。当Woker2执行完,再置flag为flase,唤醒Woker1,直到任务数为空。
Q3.互斥访问
3.1 修改TestUnSynchronizedThread.java源代码使其可以同步访问。(关键代码截图,需出现学号)
//201521123013
public static synchronized void addId() {
id++;
}
public static synchronized void subtractId() {
id--;
}
3.2 进一步使用执行器改进相应代码(关键代码截图,需出现学号)
int n=3;
List<Callable<Object>> listtask=new ArrayList<>(); //创建Callable<Object>类型的listtask
ExecutorService exec=Executors.newCachedThreadPool();
for (int i = 0; i < n; i++) {
listtask.add(Executors.callable(new Adder())); //将返回的Callable对象加入listtask
}
for (int i = 0; i < n; i++) {
listtask.add(Executors.callable(new Subtracter()));
}
exec.invokeAll(task); // 使用ExecutorService接口的invokeAll(listTask)
exec.shutdown();
System.out.println(Counter.getId());
System.out.println("main end");
Q4.线程间的合作:生产者消费者问题
4.1 运行MyProducerConsumerTest.java。正常运行结果应该是仓库还剩0个货物。多运行几次,观察结果,并回答:结果正常吗?哪里不正常?为什么?
- 不正常,有时会出现剩余货物还有10个,问题出现在
public synchronized void add(String t)
和public synchronized void remove()
。虽然这两个方法实现了synchronized,但是仓库只有一个当往仓库存入一个数据,而生产者和消费者的存取速度不一样,则有可能出现生产者比消费者快,消费者来不及取数据,或者反之,消费者取不到数据。
4.2 使用synchronized, wait, notify解决该问题(关键代码截图,需出现学号)
public synchronized void add(String t) {
while(repo.size()>=capacity){
try{
wait();
System.out.println("仓库已满!无法添加货物。");
}catch (Exception e) {
// TODO: handle exception
}
}
repo.add(t);
notifyAll();
}
public synchronized void remove() {
while(repo.size()<=0){
try{
wait();
System.out.println("仓库无货!无法从仓库取货");
}catch (Exception e) {
// TODO: handle exception
}
}
repo.remove(0);
notifyAll();
}
4.3 选做:使用Lock与Condition对象解决该问题。
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public synchronized void add(String t) {
lock.lock();
try{
while(repo.size()>=capacity){
try{
condition.await();
System.out.println("仓库已满!无法添加货物。");
}catch (Exception e) {
// TODO: handle exception
}
}
repo.add(t);
condition.signal();
}finally {
lock.unlock();
}
}
public synchronized void remove() {
try{
while(repo.size()<=0){
try{
condition.await();
System.out.println("仓库无货!无法从仓库取货");
}catch (Exception e) {
// TODO: handle exception
}
}
repo.remove(0);
condition.signal();
}finally {
lock.unlock();
}
}
Q5.查询资料回答:什么是线程安全?(用自己的话与代码总结,写自己看的懂的作业)
- 什么是线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
- 也就是当多个线程访问同一资源时才有线程安全的问题,我们要保证每次运行的结果跟单线程运行结果一样,就必须保证其在对共享资源进行操作的时候不被打扰,这就需要用到synchronized关键字,通过让访问共享资源的线程获得对象锁以获得操作权,而其他线程处于等待中。
class Counter {
private static int id = 0;
//当有线程1先对其调用addId方法,另一线程2调用subtractId方法,
public static synchronized void addId() {
id++; //线程1获得对象锁(线程2锁池中等待获得锁)对其id++,执行完后,释放this上的对象锁,
}
public static synchronized void subtractId() {
id--; //另一线程2获得对象锁,对其id--,然后释放对象锁。
}
public static int getId() {
return id; //最后获得的id才会为0,线程安全
}
}
Q6.选做:实验总结
6.1 4-8(CountDownLatch)实验总结
- 创建等待的CountDownLatch对象,因为CountDownLatch类是一个同步计数器,构造时传入int参数,该参数就是计数器的初始值,所以
CountDownLatch Latch=new CountDownLatch(n);
。然后调用Executors.newFixedThreadPool();
创建固定线程数的线程池。 - countDown()方法,计数器减1,如果计数器没有达0,那么await()方法会阻塞程序继续执行,
latch.await();
可以让主线程等待子线程的结束。
6.2 4-9(集合同步问题)实验总结
Collections.synchronizedList(new ArrayList<Integer>());
6.3 较难:4-10(Callable),并回答为什么有Runnable了还需要Callable?实验总结。
3. PTA实验总结及码云上代码提交记录
3.1本周Commit历史截图
3.2PTA实验
201521123013 《Java程序设计》第11周学习总结的更多相关文章
- 201521123045 <java程序设计>第11周学习总结
201521123045 <java程序设计>第11周学习总结 1. 本周学习总结 2. 书面作业 2. 书面作业 Q1.1.互斥访问与同步访问完成题集4-4(互斥访问)与4-5(同步访问 ...
- 201521123027 <java程序设计>第11周学习总结
1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2.书面作业 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchro ...
- 2018面向对象程序设计(Java)第11周学习指导及要求
2018面向对象程序设计(Java)第11周学习指导及要求 (2018.11.8-2018.11.11) 学习目标 (1) 掌握Vetor.Stack.Hashtable三个类的用途及常用API: ...
- 面向对象程序设计(JAVA) 第11周学习指导及要求
2019面向对象程序设计(Java)第11周学习指导及要求 (2019.11.8-2018.11.11) 学习目标 理解泛型概念: 掌握泛型类的定义与使用: 掌握泛型方法的声明与使用: 掌握泛型接 ...
- 20145236 《Java程序设计》第九周学习总结
20145236 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API ...
- 2018-2019 2 20175230《Java程序设计》第九周学习总结
<Java程序设计>第九周学习总结 主要内容 MySQL数据库管理系统 1.下载 2.安装 启动MySQL数据库服务器 1.启动 2.root用户 MySQL客户端管理工具 建立连接 建立 ...
- 20175209 《Java程序设计》第九周学习总结
20175209 <Java程序设计>第九周学习总结 一.教材知识点总结 有关数据库下载中存在可能出现的问题已经在博客<数据库安装和使用过程中出现的一些问题>给出了相应的解决办 ...
- 20175208 《Java程序设计》第九周学习总结
20175208 2018-2019-2 <Java程序设计>第九周学习总结 一.教材学习内容总结: 第11章 JDBC与MySQL数据库 MySQL数据库管理系统 MySQL数据库管理系 ...
- 20175202 《Java程序设计》第九周学习总结
20175202 2018-2019-2 <Java程序设计>第九周学习总结 教材知识点总结 第11章 JDBC与MySQL数据库 MySQL数据库管理系统 MySQL数据库管理系统,简称 ...
- 20175227张雪莹 2018-2019-2 《Java程序设计》第九周学习总结
20175227张雪莹 2018-2019-2 <Java程序设计>第九周学习总结 教材学习内容总结 第十一章 JDBC数据库操作 MySQL数据库管理系统 下载安装MySQL 若下载的是 ...
随机推荐
- innodb和myisam存储引擎插入速度
--innodb和myisam存储引擎插入速度 ------------------------------------2014/05/21 MySQL 5.6 全部默认设置,插入数据9999条,性能 ...
- Java范型
泛型不用考虑对象的具体类型.优点在于,因为不用考虑对象的具体类型所以可以对一类对象执行一定的相同操作:缺点在于,因为没有考虑对象的具体类型所以就不能使用对象自带的接口函数.泛型的最佳用同是实现容器类. ...
- ORA-00119/ORA-00132
今天在启动服务器上的ORACLE时遇到如下错误: SQL> startup; ORA-00119: invalid specification for system parameter LOCA ...
- ReactiveCocoa应用篇(二)
上一篇介绍了ReactiveCocoa的常用类,已经基本满足项目中的简单应用要求,但是针对复杂的功能还需要其它的类来协同处理.ReactiveCocoa提供了强大的流程处理功能来解决复杂的问题,包括事 ...
- css的颜色表示,与透明度
今天是第一天开始写博客.主要还是想着好记性不如烂笔头.每天学点什么就记下来,也防止以后再去百度. 今天主要是一些旧知识的整理,整理中看到原来写的代码对颜色的表示有用rgb的,有用rega的,有用# ...
- node里面的c/c++模块
准备工作 node使用c++插件时需要使用node-gyp包,node-gyp把c++源码编译为二进制文件,js在调用二进制文件,编译后的二进制文件模块调用就和js的模块调用一样. npm insta ...
- 使用oschina的git服务器图文流程 (转)
参考了豆沙包的教程我自己也做了一遍也来写写我的心得和体会 由于报名参加了游戏蛮牛<刀塔传奇>开源项目,服务器+客户端,所以觉着不管时间怎么着,还是或多或少做点贡献吧.毕竟这种体验应该还是第 ...
- SQL笔记 --- 数据库设计步骤(转)
SQL笔记 --- 数据库设计步骤 目录 总体设计过程需求分析概念结构设计逻辑结构设计数据库物理设计数据库实施数据库运行和维护 总体设计过程 0 » 下一篇:vim 命令集 posted @ 2012 ...
- 80C51 数码管动态显示0~7
所使用的开发板 普中科技HC6800-ES V2.0 PC:win7 64位 编译软件: keil uversion2 烧写工具: 普中科技开发的PZ-ISP V1.82 烧写方式:热烧写 #incl ...
- /etc/profile /etc/bashrc ~/.bash_profile ~/.bashrc ~/.bash_logout 说明及区别
/etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置. /etc/bashrc:为每一 ...