发表于: 2017-09-17 22:01:17
1 625
一、 今天完成的事情
1)Java的包装类
1)引言
Java中的八种基本数据类型不是面向对象的,在实际使用的很不方便,为了解决这点不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这八个类称为包装类。
2)关系图
3)常用方法
xxx的包装类.parseXxx(“”):转换数据类型,这里xxx指的是基本数据类型
例如:Integer.parseInt(“22”)
2)多线程
1)引例
首先看一个程序,Demo类继承Thread类并重写其中的run()方法。
test1方法中创建两个Demo实例,并开启run方法的执行。
输出结果:
按照惯例,输出结果应该是先输出01234执行完d1的run方法后再输出01234执行d2的方法,即0123401234,这里的结果却是0012123434。再看看输出的当前线程,先是1号线程,然后0号线程,而后1号线程,最后0号线程。似乎两个线程的交替执行影响了结果,实际上,这便是多线程的体现。
2)多线程
进程,是指正在运行中的程序。线程,进程中执行任务的执行流。多线程,则指的是进程中多个任务由多个线程并发执行。
Java中每个任务都是Runnable接口的实例,也称为可运行对象。而线程,本质上是便于任务执行的对象。
运行流程大致是:创建一个线程,线程调用start()方法告诉jvm该线程准备运行,jvm通过调用run()方法执行任务。
Runnable接口中只有一个run()方法,用于执行线程的任务
3)多线程的使用
方式一:任务类继承Thread类,并重写run()方法(Thread类实现了Runnable接口),通过Thread类开启线程。参考引例,这种方法将任务和运行任务的机制混合在一起,并不推荐。
方式二:任务类实现Runnable接口,重写run()方法,通过Thread(Runnable target)构造函数传入任务类创建一个Thread类,之后由Thread控制线程。这种方法将任务与线程分离,是更为优秀的设计。
4)线程的常用方法
start():开启线程,告诉jvm开始执行任务
yield():暂停线程
sleep(long millis):线程休眠mills的时间
join():使其它线程等待此线程执行结束(可以说是让此线程优先执行?)
setPriority(int newPriority):设置线程的优先级。线程中存在执行的优先级,从1-10递增,对于优先级高的线程通常需要结合yield()或sleep()方法给低优先级或相同优先级的线程一个运行的机会。
5)线程池
对于多线程执行多任务的情况,每次为一个任务创建一个线程并不够高效。Java提供Executor接口来执行线程池中的任务,提供ExecutorService接口来管理和控制任务。通过Executors类来创建线程池。
示例:
6)线程安全问题
多线程使用时,如果多个线程执行同一任务,也就是说一个共享资源被多个线程访问,这可能会遭到破坏。引发的问题有可能是丢失修改/不可重复读/读‘脏’数据等。
下面来看一个丢失修改的例子:
运行数次,得到的结果不是从1到100而是怪异的:
分析原因:
开启线程1时,读取到num = 0,在执行num+=1之前又开启了线程2,也读取到num=0,之后线程1将num+=1,即此时num=1,但对于线程2来说,读取到的num=0,执行num+=1,于是最后num=1而不是2。这也就是发生了丢失修改,线程1修改的数据没有被线程2读取到。
7)同步
对于多线程引发的安全问题,可以通过同步来解决,使用关键字synchronized。
在方法上加上synchronized关键字,这称为同步方法:
或者使用同步块,其中this作为此代码块的锁,只有执行完同步块中的代码,才能释放锁:
8)利用加锁同步
同步实际是隐式地加锁,Java可以显式地加锁,使用创建一个锁对象。
9)死锁
两个或多个线程需要在几个共享对象上获取锁,可能导致死锁。也就是说,每个线程已经锁定一个对象,而且正在等待锁定另一个对象,每个线程都陷入等待的状态。
二、 明天计划的事情
1)回顾异常类
三、 遇到的问题
四、 收获
1)重新看了多线程的书发现真是知识量巨大,这里只是稍微说了一下,还有线程间通信,监视器,阻塞队列。。。一堆没学。
评论