Java学习笔记十五
26.
下面介绍synchronized代码块,个人以为,重要度远远高于单纯的修饰synchronized方法:
一方面:高效率!
另一方面:后面涉及到的wait和notify方法,都要涉及
Synchronized要修饰一个对象
即:synchronized(Object);
表示将对象object上锁,这里的object对象其实是没有用的,只是说明被上锁,个人建议使用this关键字,表示将当前对象上锁!
看下面的synchronized代码块代码同样实现了两个方法的顺序执行:
package thread;
public class BlockTest
{
public static void main(String[] args)
{
Block block = new Block();
ThreadTestX test1 = new ThreadTestX(block);
ThreadTestXX test2 = new ThreadTestXX(block);
test1.start();
test2.start();
}
}
class Block
{
public void method1()
{
synchronized (this)
{
for(int i = 0; i < 15; i++)
{
System.out.println("hello :"+ i);
}
}
}
public void method2()
{
synchronized(this)
{
for(int i = 0 ; i <15; i ++)
{
System.out.println("world!"+ i);
}
}
}
}
class ThreadTestXextends Thread
{
private Blockblock;
public ThreadTestX(Block block)
{
this.block = block;
}
@Override
public void run()
{
block.method1();
}
}
class ThreadTestXXextends Thread
{
private Blockblock;
public ThreadTestXX(Block block)
{
this.block = block;
}
@Override
public void run()
{
block.method2();
}
}
27.
Deadlock:
所谓死锁<DeadLock>:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程.
产生deadlock的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之
一不满足,就不会发生死锁。
28.
一个线程就是一个类!
29.
Object类中的wait 、和 notify方法是用来处理线程的方法,既然定义在Object类中,两个方法的重要程度可见一斑:
两个方法的使用上都很复杂:通过阅读API获得更多对方法的理解:
The current thread must own this object'smonitor. The thread releases ownership of this monitor and waits until anotherthread notifies threads waiting on this object's monitor to wake up eitherthrough a call to thenotify
method or the notifyAll
method. The thread then waits until it can re-obtain ownership ofthe monitor and resumes execution
“当前的线程必须要获得对象的锁!”
实现这个条件的做法就是wait 方法一定要定义在synchronized方法中或者synchronized代码块中;
线程必须要两次获得锁才能完全的执行synchronized中的所有内容;
当第一次调用到达wait方法时,The thread realeases ownership of this monitor and waituntil another thread notifies threads waiting on this …
线程会暂时释放锁的拥有权,等待其他线程的notify方法或者notifyAll方法唤醒该线程,继续执行代码!
30.
下面一个程序要求定义两个线程类,一个实现将目标加一,一个实现将目标减一,目标初始值为零,要求加一减一交替进行;
显然的单纯调用synchronized是无法满足条件的,需要使用wait,和notify方法;
package thread;
public class ThreadTest
{
public static void main(String[] args)
{
ThreadDemo2 demo = new ThreadDemo2();
ThreadIncrease test1 = new ThreadIncrease(demo);
ThreadDecrease test2 = new ThreadDecrease(demo);
test1.start();
test2.start();
}
}
class ThreadDemo2
{
private int num = 0;
public synchronized void Increase()
{
/*
* 下面的代码是核心代码
* 什么时候要让线程等待,当然是不符合条件的时候
* 目的是想让num = 0的时候才执行加一的操作,当num不等于零的时候会执行wait等待通知
* 当通知num已经变为0时,wait结束,执行下面语句num++;
* 然后执行notify方法!
* 当然的一说Java中的synchronized总是伴随着wait和notify方法共同的存在;
*/
if(num != 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
num ++;
System.out.println(num);
notify();
}
public synchronized void decrease()
{
if(num == 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
num --;
System.out.println(num);
notify();
}
}
class ThreadIncreaseextends Thread
{
private ThreadDemo2demo;
public ThreadIncrease(ThreadDemo2 demo)
{
this.demo = demo;
}
@Override
public void run()
{
for(int i = 0 ; i < 15; i ++)
{
demo.Increase();
}
}
}
class ThreadDecreaseextends Thread
{
private ThreadDemo2demo;
public ThreadDecrease(ThreadDemo2 demo)
{
this.demo = demo;
}
@Override
public void run()
{
for(int i = 0 ; i < 15; i ++)
{
demo.decrease();
}
}
}
31.
可惜的是上面的代码仍然有着致命的弱点,线程并不仅仅有两个,而且是两个相对的线程!
致命的弱点在于: 当线程在wait的时候它并不知道其他的线程到底做了什么!
现在我们将增加一个Increase线程类,和一个Decrease线程类
,并且调用它们的start方法运行后,你将看到这样的结果:
我们足以看到代码的脆弱性,为什么会出现这种情况,更糟糕的是结果是随机的!上面已经说得很清楚了:当线程在wait的时候,它不知道其他的线程正在做什么,
所以需要将代码变得更加健壮:
我们举一个为什么会出现这种情况的原因之一:
我们假设线程1、2调用增加方法,线程3、4调用减少方法
假设线程3 先访问了减少方法,因为此时num的值为0,所以wait,并且交出ownership,假设线程4又访问了减少方法,同样的wait,并且交出所有权,再假设线程1访问了增加方法,将num的值变为1,并且调用notify方法,假设notify了线程3,线程3将num的值变为0;并且notify,如果此时notify了线程4,那么悲剧就会发生了,线程4醒来后,会继续将num减一,变为-1,一步错,后面就全错了;
缺点就在于notify的随机性,所以在某个wait方法被唤醒时,增加判断条件,如果不符合条件,继续wait,显然 while循环是最合适的
!
全部的变化只需要将 if 改为 while!!
由于num是成员变量被线程共享,每当wait被唤醒,都会判断一次;
package thread;
public class ThreadTest
{
public static void main(String[] args)
{
ThreadDemo2 demo = new ThreadDemo2();
ThreadIncrease test1 = new ThreadIncrease(demo);
ThreadDecrease test2 = new ThreadDecrease(demo);
ThreadIncrease test3 = new ThreadIncrease(demo);
ThreadDecrease test4 = new ThreadDecrease(demo);
test1.start();
test2.start();
test3.start();
test4.start();
}
}
class ThreadDemo2
{
private int num = 0;
public synchronized void Increase()
{
/*
* 下面的代码是核心代码
* 什么时候要让线程等待,当然是不符合条件的时候
* 目的是想让num = 0的时候才执行加一的操作,当num不等于零的时候会执行wait等待通知
* 当通知num已经变为0时,wait结束,执行下面语句num++;
* 然后执行notify方法!
* 当然的一说Java中的synchronized总是伴随着wait和notify方法共同的存在;
*/
while(num != 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
num ++;
System.out.println(num);
notify();
}
public synchronized void decrease()
{
while(num == 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
num --;
System.out.println(num);
notify();
}
}
class ThreadIncreaseextends Thread
{
private ThreadDemo2demo;
public ThreadIncrease(ThreadDemo2 demo)
{
this.demo = demo;
}
@Override
public void run()
{
for(int i = 0 ; i < 15; i ++)
{
try
{
Thread.sleep((long)(Math.random()*1000));
}
catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
demo.Increase();
}
}
}
class ThreadDecreaseextends Thread
{
private ThreadDemo2demo;
public ThreadDecrease(ThreadDemo2 demo)
{
this.demo = demo;
}
@Override
public void run()
{
for(int i = 0 ; i < 15; i ++)
{
try
{
Thread.sleep((long)(Math.random()*1000));
}
catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
demo.decrease();
}
}
}
32.
Object 中最后一个方法—— colone;
首先介绍浅克隆,被克隆的类必须实现了Cloneable接口
该接口是一个标识接口!
克隆的只是对象!
对于任何的拷贝对象X;一定有
1. X.clone() != X;
即克隆的对象与原对象肯定不是一个对象;
1.X.clone().getClass() ==x.getClass();
一个类不管有多少个对象,它们都有着共同的一个类!
2.如果设计的合适的话
x.clone().equals(x)是正确的;
下面是浅克隆:
package com.jianjian.clone;
public class CloneTest1
{
public static void main(String[] args)throws CloneNotSupportedException
{
Person person = new Person();
person.setAge(20);
person.setName("yangmanman");
Person person1 = (Person)person.clone();//注意到返回的对象是Object类型的,不要忘记类型转换;
System.out.println(person1.getAge());
System.out.println(person1.getName());
System.out.println(person1 == person);
System.out.println(person1.getClass() == person.getClass());
System.out.println(person1.equals(person));//我重写了equals方法;将结果返回true
}
}
class Person implements Cloneable
{
private int age;
private Stringname;
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Override//需要重写clone方法;
protected Object clone()throws CloneNotSupportedException
{
Object object = super.clone();
return object;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name ==null) ? 0 :name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj ==null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name ==null)
{
if (other.name !=null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
}
33.
关于深克隆,以后深究
Java学习笔记十五相关推荐
- python复制指定字符串_python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)...
python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...
- windows内核开发学习笔记十五:IRP结构
windows内核开发学习笔记十五:IRP结构 IRP(I/O Request Package)在windows内核中,有一种系统组件--IRP,即输入输出请求包.当上层应用程序需要访问底层输入输 ...
- java学习记录十五:集合二Collections、Set、Map
java学习记录十五:集合二 一.Collections工具类 一.解释 二.常用方法 1.打乱集合顺序 2.按照默认规则排序 3.按指定规则排序 4.批量添加元素 二.可变参数 一.解释 二.写法 ...
- Polyworks脚本开发学习笔记(十五)-用Python连接Polyworks的COM组件
Polyworks脚本开发学习笔记(十五)-用Python连接Polyworks的COM组件 用Polyworks脚本开发,没有高级语言的支持,功能难免单一,一些比较复杂的交互实现不了,界面和报告也很 ...
- Java学习 第十五天
Java学习 第十五天 第一章 StringBuilder类 1.1 字符串的不可变 1.2 StringBuilder概述 1.3 构造方法 1.4 两个常用方法 1.4.1 append方法 1. ...
- IOS之学习笔记十五(协议和委托的使用)
1.协议和委托的使用 1).协议可以看下我的这篇博客 IOS之学习笔记十四(协议的定义和实现) https://blog.csdn.net/u011068702/article/details/809 ...
- Mr.J-- jQuery学习笔记(十五)--实现页面的对联广告
请看之前的:Mr.J-- jQuery学习笔记(十四)--动画显示隐藏 话不多说,直接上demo <!DOCTYPE html> <html lang="en"& ...
- 世界是有生命的(通向财富自由之路学习笔记十五)
最近因为工作调度的事情,有了一段空闲的日子,有比较多的时间来回望自己走过的路以及如何走好以后的路.之前忙得很少时间来写博文,很少时间来写读书笔记,逐渐将自己一些很好的习惯丢弃了.从今天起将重拾写博文的 ...
- Java学习 第十五章 成员变量和局部变量的区别 / 三大特征之一 (封装性)/构造方法 /private关键字
第十五章 局部变量和成员变量: 1.定义位置不一样 局部变量:在方法内部定义 成员变量:在方法的外部,直接写在类当中 2.作用范围不一样 局部变量:只能在方法当中使用 成员变量:整个类都可以使用 3. ...
最新文章
- 【Web】Rest API 验证授权如何做?
- 老生常谈:文字常量区的那点事
- C++primer笔记之关联容器
- Programming Pearls Essay 01
- 警告: deleting object of polymorphic class type which has non_virtual destructor
- 003_JavaScript实现
- asp.net session 如何知道是哪个浏览器客户端_微服务下的分布式session管理
- linux上查看gitlab日志,如何查看Gitlab的版本?
- 钉钉微应用怎么进入_钉钉微应用开发免登流程
- 路由器与交换机的工作原理
- mysql 赋给用户权限 grant all privileges on
- ubuntu14.04+eigen3安裝(亲测)
- 使用Docker运行oracle11g企业版和简单配置
- 模式窗口showModalDialog的用法总结
- 上一篇的改进!!!!!
- 读jQuery源码释疑笔记3
- 科研论文检索方法入门(计算机领域)
- android客户端设计,图文详解Android客户端界面设计教程
- J2SE J2EE J2ME名字的来历
- Opencv中视频播放与进度控制