黑马程序员
五十七
定义了一个静态内部类的话,如果在方法主函数中创建了一个这个静态内部类的对象,这个对象要马上调用这个内部静态类的一个方法。
在某个类中用static扩住的代码,在程序运行的首次仅仅加载一次。
五十八
分割图片
要有揣测能力。
两个线程要想同步,不许有相同的监视器。很好理解,就比方说是有同一个长官领导下的。当然有类监视器,也有对象监视器。
五十九
ThreadLocal实现线程范围的共享变量
Thread的作用与目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。
每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值,在线程结束时要记住调用ThreadLocal.clear()方法。
ThreadLocal应用场景:
1订单处理包含一系列操作:减少库存量,增加一条流水台帐,累加公司应收款,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。
2银行转帐包含以系列操作:把转出的帐户余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的帐户对象的方法。
3例如Struct2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。
实验案例:定义一个全局变量的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共相同一份数据。
实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。
1对基本类型的数据的封装,这种应用相对很少见。
2对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。
实验步骤:
1先在MyThreadData类中定义一个访问权限为public的ThreadLocal类型的变量x,直接对这个x进行读写操作;
2将变量的x的访问权限定义为private,MyThreadLocalData上定义相应的set和get方法对向变量x中存储和检索数据;
3将MyThreadLocalData类自身变成一个具有业务功能的对象,但每个线程仅有该类的一个实例对象,即对于不同的线程来说,MyThreadLocalData.getMyData静态方法拿到的对象都不同,但对于同一个线程来说,不管调用MyThreadData.getMydata多少次和在哪里调用,拿到的都是同一个MyThreadData对象。先将MyThreadData封装成具有业务功能的对象,然后设计getMyData方法的定义,最后定义getMyData方法要操作的ThreadLocal变量和编写具体的代码。
ThreadLocal类的应用举例:
public class ThreadLocalTest{
public static void main(String[] args)
{
ExecutorService service=Executor.newFixedThreadPool(2);
final A a=new A();
final B b=new B();
}
六十
Java5中的线程并发库
1看java.util.concurrent包及子包的API帮助文档
2线程池的概念与Executors类的应用
---创建固定大小的线程池
---创建缓存线程池
---创建单一线程池
关闭线程池
shutdown与shutdownNow的比较
ScheduleExecutorService
在int变量之前加上volatile关键字后,当操作该变量时则具有互斥性。等效于在synchronized方法中使用该变量。
看包的API帮助文档,可以先找到该包下的某个类的帮助页面,然后在该页面的顶部单击package超链接。了解atomic和lock这两个子包。还有locks子包。
固定大小的线程池&缓存线程池-------------
步骤1:用3个大小的固定线程池去执行10个内部循环10次就结束任务,为了观察固定线程池下的其他任务一直再等待,希望打印出正在执行的线程名,任务号和任务内部的循环次数,刚开始看到只有3个线程在执行,并看到任务前赴后继的效果。注意:这10个任务要用各自独立的runnable对象,才能看到任务的序号。
步骤2:改为缓存线程池,可以看到当前有多个任务,就会分配多少个线程为之服务。
六十一
Callable&Future
Future取得的结果类型和Callable返回的结果类型必须一致,这是通过泛型来实现的。
Callable要采用ExecutorService的submit方法提交,返回的future对象可以取消任务。
CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。
六十二
Lock&Condition实现线程同步通信
两个线程执行的代码片段要实现同步互斥的效果,他们必须用同一个Lock对象。
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读得时候上读锁,写的时候上写锁!
在等待Condition时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。
一个锁内部可以有多个Condition,即有多路等待和通知,可以参看jdk1.5提供的
用finally解锁。
六十三
线程通信
1.5中的condition的引入,解决了以前只能引入一个信号量的问题,1.5以后可以引入多个。
六十四
Semaphhore实现信号灯
Semaphore可以轻松完成信号量控制,即控制同时访问的线程个数,例如,实现一个文件允许的并发访问数。
Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。
与阻塞队列有些相似,但也不同,阻塞队列是一方存放数据,另一方释放数据,Semaphore通常则是由同一放设置和释放信号量。
我的理解:Lock类的设置是为了将代码中的不必要的并发性消除,实现原子性。
其他同步工具类
CyclicBarrier:表示大家彼此等待,大家结合好后才开始出发,分散活动后又在指定的地点集合碰面。
CountDownLatch:表示一个人(也可以是多个人)等待其他所有人来通知他,这犹如一个计划需要多个领导都签字后才能继续向下实施。还可以实现一个人通知多个人的效果,类似裁判一声口令,运动员开始奔跑。
Exchanger
用于实现两个人之间的数据交换,每个人在完成一定的事物 后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据。
六十五
可阻塞的队列
ArrayBlockingQueue
---只有put方法和take方法才具有阻塞功能
用了三个空间的队列来演示阻塞队列的功能和效果。
用两个具有1个空间的队列来实现同步通知的功能。
同步集合
传统方式下用Collections工具类提供的方法来获得同步集合。
Java5中提供了如下一些同步集合类:
---ConcurrentHashMap
---CopyOnWriteArrayList
---CopyOnWriteArraySet
同步方法synchronizedCollection
BlockingQueue类 ArrayBlockingQueue类
public class ArrayBlockQueue{
public static void main(){
final BlockingQueue queue=new ArrayBlockQueue(3);
for(int i=0;i<2;i++){
new Thread(){
public void run(){
while(true){
try{
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName()+"准备放数据!");
queue.put(1);
System.out.println(Thread.currentThread().getName()+"已经放好了数据,"+"队列目前有"+queue.size()+"个数据");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}.start();
}
new Thread(){
public void run(){
while(true){
try{
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"准备取数据!");
queue.take();
System.out.println(Thread.currentThread().getName()+"已经取走数据"+"队列目前有"+queue.size()+"个数据");
} catch{
e.printStackTrace();
}
}
}
}
}
}
深拷贝就是实现java.lang.Cloneable接口,然后重写clone()方法,最简单的方法就是在clone()方法中直接把对象序列化到磁盘上再反序列化回来,这样不用判断就可以得到一个深copy的结果。如果不了解序列化的作法,可以看一下ObjectOutputstream和ObjectInputStream.
序列化就是把一个Java对象转换成二进制进行磁盘上传输或者网络流行的传输,反序列化的意思就是把这个接受到的二进制流重新组装成原来的对象逆过程。
五十七
定义了一个静态内部类的话,如果在方法主函数中创建了一个这个静态内部类的对象,这个对象要马上调用这个内部静态类的一个方法。
在某个类中用static扩住的代码,在程序运行的首次仅仅加载一次。
五十八
分割图片
要有揣测能力。
两个线程要想同步,不许有相同的监视器。很好理解,就比方说是有同一个长官领导下的。当然有类监视器,也有对象监视器。
五十九
ThreadLocal实现线程范围的共享变量
Thread的作用与目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。
每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值,在线程结束时要记住调用ThreadLocal.clear()方法。
ThreadLocal应用场景:
1订单处理包含一系列操作:减少库存量,增加一条流水台帐,累加公司应收款,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。
2银行转帐包含以系列操作:把转出的帐户余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的帐户对象的方法。
3例如Struct2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。
实验案例:定义一个全局变量的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共相同一份数据。
实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。
1对基本类型的数据的封装,这种应用相对很少见。
2对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。
实验步骤:
1先在MyThreadData类中定义一个访问权限为public的ThreadLocal类型的变量x,直接对这个x进行读写操作;
2将变量的x的访问权限定义为private,MyThreadLocalData上定义相应的set和get方法对向变量x中存储和检索数据;
3将MyThreadLocalData类自身变成一个具有业务功能的对象,但每个线程仅有该类的一个实例对象,即对于不同的线程来说,MyThreadLocalData.getMyData静态方法拿到的对象都不同,但对于同一个线程来说,不管调用MyThreadData.getMydata多少次和在哪里调用,拿到的都是同一个MyThreadData对象。先将MyThreadData封装成具有业务功能的对象,然后设计getMyData方法的定义,最后定义getMyData方法要操作的ThreadLocal变量和编写具体的代码。
ThreadLocal类的应用举例:
public class ThreadLocalTest{
public static void main(String[] args)
{
ExecutorService service=Executor.newFixedThreadPool(2);
final A a=new A();
final B b=new B();
}
六十
Java5中的线程并发库
1看java.util.concurrent包及子包的API帮助文档
2线程池的概念与Executors类的应用
---创建固定大小的线程池
---创建缓存线程池
---创建单一线程池
关闭线程池
shutdown与shutdownNow的比较
ScheduleExecutorService
在int变量之前加上volatile关键字后,当操作该变量时则具有互斥性。等效于在synchronized方法中使用该变量。
看包的API帮助文档,可以先找到该包下的某个类的帮助页面,然后在该页面的顶部单击package超链接。了解atomic和lock这两个子包。还有locks子包。
固定大小的线程池&缓存线程池-------------
步骤1:用3个大小的固定线程池去执行10个内部循环10次就结束任务,为了观察固定线程池下的其他任务一直再等待,希望打印出正在执行的线程名,任务号和任务内部的循环次数,刚开始看到只有3个线程在执行,并看到任务前赴后继的效果。注意:这10个任务要用各自独立的runnable对象,才能看到任务的序号。
步骤2:改为缓存线程池,可以看到当前有多个任务,就会分配多少个线程为之服务。
六十一
Callable&Future
Future取得的结果类型和Callable返回的结果类型必须一致,这是通过泛型来实现的。
Callable要采用ExecutorService的submit方法提交,返回的future对象可以取消任务。
CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。
六十二
Lock&Condition实现线程同步通信
两个线程执行的代码片段要实现同步互斥的效果,他们必须用同一个Lock对象。
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读得时候上读锁,写的时候上写锁!
在等待Condition时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。
一个锁内部可以有多个Condition,即有多路等待和通知,可以参看jdk1.5提供的
用finally解锁。
六十三
线程通信
1.5中的condition的引入,解决了以前只能引入一个信号量的问题,1.5以后可以引入多个。
六十四
Semaphhore实现信号灯
Semaphore可以轻松完成信号量控制,即控制同时访问的线程个数,例如,实现一个文件允许的并发访问数。
Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。
与阻塞队列有些相似,但也不同,阻塞队列是一方存放数据,另一方释放数据,Semaphore通常则是由同一放设置和释放信号量。
我的理解:Lock类的设置是为了将代码中的不必要的并发性消除,实现原子性。
其他同步工具类
CyclicBarrier:表示大家彼此等待,大家结合好后才开始出发,分散活动后又在指定的地点集合碰面。
CountDownLatch:表示一个人(也可以是多个人)等待其他所有人来通知他,这犹如一个计划需要多个领导都签字后才能继续向下实施。还可以实现一个人通知多个人的效果,类似裁判一声口令,运动员开始奔跑。
Exchanger
用于实现两个人之间的数据交换,每个人在完成一定的事物 后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据。
六十五
可阻塞的队列
ArrayBlockingQueue
---只有put方法和take方法才具有阻塞功能
用了三个空间的队列来演示阻塞队列的功能和效果。
用两个具有1个空间的队列来实现同步通知的功能。
同步集合
传统方式下用Collections工具类提供的方法来获得同步集合。
Java5中提供了如下一些同步集合类:
---ConcurrentHashMap
---CopyOnWriteArrayList
---CopyOnWriteArraySet
同步方法synchronizedCollection
BlockingQueue类 ArrayBlockingQueue类
public class ArrayBlockQueue{
public static void main(){
final BlockingQueue queue=new ArrayBlockQueue(3);
for(int i=0;i<2;i++){
new Thread(){
public void run(){
while(true){
try{
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName()+"准备放数据!");
queue.put(1);
System.out.println(Thread.currentThread().getName()+"已经放好了数据,"+"队列目前有"+queue.size()+"个数据");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}.start();
}
new Thread(){
public void run(){
while(true){
try{
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"准备取数据!");
queue.take();
System.out.println(Thread.currentThread().getName()+"已经取走数据"+"队列目前有"+queue.size()+"个数据");
} catch{
e.printStackTrace();
}
}
}
}
}
}
深拷贝就是实现java.lang.Cloneable接口,然后重写clone()方法,最简单的方法就是在clone()方法中直接把对象序列化到磁盘上再反序列化回来,这样不用判断就可以得到一个深copy的结果。如果不了解序列化的作法,可以看一下ObjectOutputstream和ObjectInputStream.
序列化就是把一个Java对象转换成二进制进行磁盘上传输或者网络流行的传输,反序列化的意思就是把这个接受到的二进制流重新组装成原来的对象逆过程。
发表评论
-
黑马程序员Java培训和Android培训Java技术五
2011-07-02 22:42 760黑马程序员 五十一 同Java技术四的五十创建动态类的对象及调 ... -
黑马程序员Java培训和Android培训Java技术四
2011-07-02 22:38 761黑马程序员 四十一 泛型方法的练习题 1编写一个泛型方法,自动 ... -
黑马程序员Java培训和Android培训Java技术三
2011-07-02 22:32 778黑马程序员 三十一 对ja ... -
黑马程序员Java培训和Android培训Java技术二
2011-07-02 22:27 669黑马程序员 二十一 字 ... -
黑马程序员Java培训和Android培训Java 技术一
2011-07-02 22:19 691黑马程序员 十一 基本数据类型的自动拆箱与装箱 自动装箱: I ... -
黑马程序员Java培训和Android培训Java 技术
2011-07-02 22:14 717黑马程序员 一 二 三 ecl ...
相关推荐
"黑马程序员java基础试题、笔记"这个压缩包资源为Java初学者和希望加入"黑马程序员"培训课程的学员提供了丰富的学习材料。这些资源包括面试问题合集、整理的资料、Android面试题、学员入学面试总结、面试技巧、必须...
总而言之,《黑马程序员Android学习笔记》是一份全面的学习资源,它不仅教授Android开发的基础,还覆盖了许多实际开发中可能遇到的问题和解决方案。通过深入学习和实践,你将能够熟练掌握Android应用开发,成为一名...
【Java基础辅导班教程...总之,"黑马程序员_Java基础辅导班教程课件[第01期]第13天"是一个全面覆盖Java基础的教程,结合课堂内容、视频、源码和图解,为学员提供了丰富的学习资源,助力他们稳步迈进Java开发的世界。
### 黑马程序员Android视频教程知识点解析 #### 一、Android基础概述 - **定义与特点**:Android是一种基于Linux内核(不包括GNU组件)的开源操作系统,主要用于移动设备。它由Google公司及其领导下的开放手机联盟...
《黑马程序员_从零开始征服Android之旅(第二季)源码和笔记(上)》是一部针对初学者的全面Android开发教程,旨在帮助学员系统地掌握Android应用开发的基础知识和实战技巧。通过本教程的学习,你可以从理论出发,...
《黑马程序员_从零开始征服Android之旅(第一季)源码和笔记》是一份全面的Android开发学习资源,旨在帮助初学者系统地掌握Android开发技术,实现从理论到实践的跨越。这份资料涵盖了一系列关键知识点,包括但不限于...
【标题】:“黑马程序员入学测试题”是一份用于评估编程基础和理解能力的测试集,主要针对准备加入黑马程序员培训课程的学生。这份测试题旨在帮助新手程序员检验自己的知识水平,以便更好地适应学习环境。 【描述】...
《黑马程序员毕向东Java基础课堂完整版文档》是一份全面且深入的Java学习资源,由知名教育机构黑马程序员的讲师毕向东倾力打造。这份资料涵盖了从Java编程基础到高级特性的全过程,旨在帮助初学者系统地掌握Java编程...
### 安卓黑马程序员课程知识点概览 #### 1. XML编程 ...以上为“安卓黑马程序员课表”中涉及的主要知识点概览,通过系统的学习与实践,学员能够建立起坚实的IT技术基础,并具备实际项目开发的能力。
根据提供的文件信息,这里将对“黑马程序员最新一期高清教学视频”进行详细的解析与扩展,以便更好地理解其中可能涵盖的知识点和技术内容。 ### 黑马程序员教学视频概述 #### 标题解读:“黑马程序员最新一期高清...
在本资源包“黑马程序员 从零开始征服Android之旅(第一季)源码和笔记 下”中,我们聚焦于Android应用程序开发的基础与实践。通过学习,你可以系统地掌握Android开发的核心概念,逐步成长为一名合格的Android开发者...
2015/1/17 星期六 Android应用开发-数据存储和界面展现 2015/1/18 星期日 Android应用开发-数据存储和界面展现 2015/1/19 星期一 2015/1/20 星期二 Android应用开发-网络编程 2015/1/21 星期三 Android应用开发-...
Java自学宝典是针对初学者和有一定基础的学习者设计的一套完整的Java学习资源,由知名的教育机构黑马程序员出品。这份源代码压缩包包含了书中各个章节的实例代码,旨在帮助学习者深入理解Java编程语言的核心概念和...
在本课程中,“黑马程序员”将引导我们逐步学习如何在短短两小时内编写一个Android应用程序。这个教程特别关注的是第5天的内容,主要涉及到天气预报应用的开发,包括数据获取、数据显示以及网络图片的查看功能。下面...
根据提供的文件信息,我们可以推断出这是一套由知名IT教育机构“黑马程序员”出品、由讲师毕向东主讲的Java基础教学视频。由于实际视频内容无法直接获取,本篇将依据标题、描述以及部分标签内容,综合分析并展开相关...
【标题】"黑马74期 安全卫士android源码"揭示了这是一份针对Android平台的安全卫士应用的源代码,源自知名的黑马程序员培训课程的第74期。这个安全卫士软件旨在保护用户的Android设备,提供了一系列功能来确保设备的...
红孩子电子商城项目,由知名教育机构传智播客和黑马程序员联合推出,旨在为学员提供一套完整的电商系统开发实践案例。该项目涵盖了客户端和服务端的源代码,以及详尽的开发文档,是学习和理解电商系统开发的宝贵资料...
在"黑马程序员_Java基础辅导班教程课件[第01期]第10天"中,我们聚焦于Java编程语言的基础知识,这是一门面向初学者的课程,旨在帮助学员快速掌握Java的核心概念。通过这个阶段的学习,学员将能够理解并运用Java的...
在本课程中,“黑马程序员”将引导我们逐步学习如何在短短两小时内编写一个基础的安卓应用程序。这是一门针对初学者的安卓编程教程,重点在于快速掌握安卓开发的基础概念和实践技能。第03天的课件源码包含了构建安卓...