Java学习打卡:第二十五天
Java养成计划(打卡第25天)
内容管理
今天分享一些基本的,以前漏掉的java知识,查漏补缺最好的方式还是实践,只有灵活的运用之后才能发现自身存在的问题。
预定义标注类型
之前你了解过一些javadoc注释,在java核心API里面包含一些预定义的标注类型,其中包含Deprecated,Override,Suppress Warrings
Deprecated
标记标注类型,当程序中的元素有更好的替代品存在时,就可以使用该类型的标注,表示该程序元素是过时的,当编译器检测到时就会警告
@Deprecated
public String getCry() {
return "ahch";
}
Override
标记标注类型,指明方法是一个重写方法,当发现子类的标注过的方法并没有覆盖超类方法时就会报错
@Override
public String getName() {
return "dog";
};
Suppress Warrings
这个标注类型包含一个String[]类型的value,用该类型的标注修饰某个程序元素时可以抑制针对该元素的警告信息
用法是
@SuppressWarrings(“deprecation”) //这就抑制了Deperated类型的警告信息
public static void mian(String[] args)
{
@SuppressWarrings("deprecation")
Object o = new Object();
o.getCry();
}
其余还有Inherited,Retention,Target等标注,等之后实例中用到的时候再谈
线程与同步
之前的了解中只是简单了解了一下多线程的两种方式一种是扩展Thread,另外一种是实现Runnable,以及简单的线程同步
两种方法的共性
- 线程是对象,一个线程是Thread类的实例或者是其子类的实例,扩展就是子类实例,实现方式就是Thread实例
- 线程通过执行特定对象的特定方法来完成相应的任务,线程启动后都是执行的线程对象的run() 方法
- 线程的启动都是通过start方法启动,不能显式调用run方法,如果调用就只是普通的方法,就不会达到多线程的目的
调用的run()方法都是线程对象的方法,这里扩展Thread类好理解,创建了几个子类线程对象,调用其方法,那么实现接口方式的线程对象是怎么回事
我们可以查看Thread类的run源码
public void run(){
if(target != null)
{
target.run();
}
}
target就是传递给构造方法的那个Runnable对象,所以只要在创建对象时指定了Runnable对象,最终执行的就是那个对象的run方法。
线程控制
除了start,run之外,Thread还有其他诸如sleep的方法,在介绍方法之前先来介绍一下线程状态与线程优先级
线程状态
之前的介绍知道线程经start()启动之后不会马上进入执行状态(running),而是县进入就绪状态,等待CPU的控制和分配,而处于执行状态下的线程也可能会被剥夺控制回到就绪(ready)状态,另外还有就是执行中的线程可能因为某些阻塞事件被迫放弃CPU控制,进入等待(waiting)状态。
执行中的线程也可能会由于某种阻塞事件而丧失继续占有CPU的理由
- 等待I/O操作的完成(比如控制台输入之类的)
- 调用sleep()方法,主动进入休眠
- 调用synchronized方法或语句不能获得相应的对象
- 一个对象不满足当前线程继续执行处理,线程主动调用wait方法
当这类事件发生时,执行的线程就会放弃CPU,进入等待状态,当阻塞事件消除时,相应的线程由等待状态转变为就绪状态等待执行,重新调度
线程优先级
在java中,每一个线程都有优先级,取值从1到10,Thread类中定义了一些与优先级有关的量
-
static int MIN_PRIORITY = 1; -
static int NORM_PRIORITY = 5 -
static int MAX_PRIORITY = 10; -
void setPriority(int newPriority) //设置线程的优先级 -
final int getPriority() //返回线程优先级,不可以重写
main线程的默认优先级为5,一个新建线程的优先级等于创建它的父线程的优先级
线程的调度策略分为先占式和轮转式,这个等之后讲到线程池的时候再提
yield() //当前线程放弃CPU进入就绪状态
这是一个Thread类的一个静态方法,该方法可以使当前执行的线程进入就绪状态
这里有两种可能
- 没有其他就绪线程存在,刚放弃的CPU马上重新获得并投入执行
- 有其他就绪线程,就要看具体的调度程序,如果优先级相同,就在其他里选择一个,如果优先级更高,那还是优先执行
sleep(long millis) //使当前执行的线程进入睡眠状态
这也是一个静态方法,使当前线程放弃CPU进入休眠状态,时间到后就绪等待调度,long型数值为毫秒
- 这个方法不能用于精确定,因为时间到后并不是马上就可以执行
执行该方法要检查InterruptedException,接下来写一个简单的计时器,线程运行时,间隔3秒输出当前所剩的时间
首先要分析,既然是计时器,那么就要有一个记录时间的函数,那就是System里面提供的currentTimeMills方法,返回1970年1、1到现在的毫秒数,之后我们创建一个线程,让这个线程休眠,这里我们只创建这一个线程,所以就会执行的
这里我们?就是依靠这个时间会自己变化,我们就让原来的时间加上一个原来的毫秒数,在沉睡期间时间是在变化的,所以就直接用max函数比较就可,只是要强制转换
package ThreadDemo;
public class ThreadDemo implements Runnable{
int allTime;
public ThreadDemo(int alltime) {
this.allTime = alltime;
new Thread(this).start();
}
@Override
public void run() {
System.out.println("Now the time is " + allTime);
long newtime = System.currentTimeMillis() + allTime* 1000;
while(true)
{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
allTime = (int)Math.max(0,(newtime - System.currentTimeMillis())/1000);
System.out.println("Now the time is " + allTime);
if(allTime == 0)
break;
}
}
public static void main(String[] args) {
new ThreadDemo(60);
}
}
这里由于主线程的影响,最开始的数据不是57,而是56,这就是因为这里不只是只有一个线程,但是之后就规律了
Now the time is 60 Now the time is 56 Now the time is 53 Now the time is 50 Now the time is 47 Now the time is 44 Now the time is 41 Now the time is 38 Now the time is 35 Now the time is 32 Now the time is 29 Now the time is 26 Now the time is 23
这里的线程的应用十分广泛,明天会继续分享剩下的同步互斥以及其他的应用~~~
|