标签:size 安全 lis 主线程等待子线程 hello pac 进程 latch 状态
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(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方法或者代码块中?
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();
}
}
}
...
Q3.互斥访问
3.1 修改TestUnSynchronizedThread.java源代码使其可以同步访问。(关键代码截图,需出现学号)
//201521044091
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)
System.out.println(Counter.getId());
System.out.println("main end");
Q4.线程间的合作:生产者消费者问题
4.1 运行MyProducerConsumerTest.java。正常运行结果应该是仓库还剩0个货物。多运行几次,观察结果,并回答:结果正常吗?哪里不正常?为什么?
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);
notify();
}
public synchronized void remove() {
while(repo.size()<=0){
try{
wait();
System.out.println("仓库无货!无法从仓库取货");
}catch (Exception e) {
// TODO: handle exception
}
}
repo.remove(0);
notify();
}
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.查询资料回答:什么是线程安全?(用自己的话与代码总结,写自己看的懂的作业)
什么是线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
Q6.选做:实验总结
6.1 4-8(CountDownLatch)实验总结
CountDownLatch Latch=new CountDownLatch(n);
。然后调用Executors.newFixedThreadPool();
创建固定线程数的线程池。latch.await();
可以让主线程等待子线程的结束。
201521044091 《Java程序设计》第11周学习总结
标签:size 安全 lis 主线程等待子线程 hello pac 进程 latch 状态
原文地址:http://www.cnblogs.com/jiemicc/p/6817938.html