发表于: 2017-11-19 20:53:44

2 595


今日完成的事情:

;先学一下线程相关知识

 

1; 进程(Processor)和线程(Thread)的区别

进程:启动一个QQ.exe就叫一个进程;接着又启动一个WeChat.exe,这叫两个进程。

线程:线程是在进程内部同时做的事情,比如在QQ里,有很多事情要同时做,就像我利用qq语音的同时又分享屏幕,这应该就是两个线程;而这些就是由多线程来实现的。

 

2;以游戏对战来学习线程相关代码

A;不使用多线程,演示游戏中的英雄对站,只有第一场结束,才开始第二场的厮杀

首先定义hero这个类,然后写上攻击方法,判断是否死亡


 

然后测试类,new四个hero对战



 

演示结果,只有李白杀死貂蝉,吕布才会杀后羿


 

 

B;使用多线程演示,两者同时进行攻击;这也正是多线程的意义所在,即在同一时间,可以做多件事情;而创建多线程有3种方式,分别是继承线程类,实现Runnable接口以及匿名类

 

1,先说通过继承线程类,重写run方法来实现

 

//Thread implements实现了接口Runnable
public class KillThread extends Thread
   
private Hero hero1;
   
private Hero hero2;
   
//有参构造
   
public KillThread(Hero hero1, Hero hero2)
       
this.hero1 = hero1;
       
this.hero2 = hero2;
   
//重写run方法
   
//启动线程是start()方法,run()并不能启动一个新的线程
   
public void run()
       
while (!hero2.isDead())
           
hero1.attackHero(hero2);

 

启动线程办法:实例化一个KillThread对象,并且调用其start方法

//实例化一个对象
KillThread killThread1 = new KillThread(one,two);
//然后调用start方法
killThread1.start();
//启动线程是start()方法,run()并不能启动一个新的线程
KillThread killThread2 = new KillThread(four,three);
killThread2.start();

 

结果,两次攻击同时进行


 

2;通过创建类实现Runnable口的类battle,简单说下

实现了接口

public class Battle implements Runnable

可以调用方法

//battle1对象实现了Runnable接口,所以有run方法,但是直接调用run方法,并不会启动一个新的线程。
Battle battle1 = new Battle(one ,two);
//在创建Thread对象的时候,battle1作为构造方法的参数传递进去,这个线程启动的时候,就会去执行battle1.run()方法了。
new Thread(battle1).start();
//必须,借助一个线程对象的start()方法,才会启动一个新的线程。
Battle battle2 =new Battle(four ,three);
new Thread(battle2).start();

 

结论也是多线程;实际上这两种方法类似,一个是继承实现接口的类Thread,自然就继承了run方法,一个是直接实现了接口,也会提供了run方法;然后就是要想启动线程必须调用start方法;前者继承了线程类,对象可以直接调用;后者是实现了接口,只能新建线程类调用start方法;然后把这个类当作参数传进去,也可以调用run方法了.

 

3;主要看一下匿名类的多线程实现原理;

不太熟悉匿名类,先了解一下概念;

匿名类指的是在声明一个类的同时实例化它,使代码更加简洁精练;通常情况下,要使用一个接口或者抽象类,都必须创建一个子类;有的时候,为了快速使用,直接实例化一个抽象类,并“当场”实现其抽象方法。既然实现了抽象方法,那么就是一个新的类,只是这个类,没有命名。这样的类,叫做匿名类

//匿名类
Thread thread1 = new Thread()
   
//继承Thread,重写run方法,直接在run方法中写业务代码
   
public void run()
       
//匿名类中用到外部的局部变量two,必须声明为final
        //
但是在JDK7以后,就不是必须加final的了
       
while (!two.isDead()) {
           
one.attackHero(two);
thread1.start();

没用过感觉很方便,但是概念不清,不太好理解,mark.

 

4;知道了怎么创建多线程,再看一下专业的进程和线程区别;

进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。

线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。

线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

多进程是指操作系统能同时运行多个任务(程序)。

多线程是指在同一程序中有多个顺序流在执行。

 

,学习一下常见的线程方法;


1,第一个就是上面用到的;Thread.sleep 表示当前线程暂停毫秒,其他线程不受影响,这也是为什么会抛InterruptedException中断异常的原因;因为暂停的时候有可能会被停止;


Thread thread3 = new Thread(() ->
   
int seconds = 0;
   
while (true) {
       
try {
           
Thread.sleep(1000);

 

2,加入主线程的方法; 所有进程,至少会有一个线程即主线程,main方法开始执行,就会有一个看不见的主线程存在,通过执行join方法,在主线程中加入该线程.主线程会等待该线程结束完毕,才会往下运行。

 

没有加入主线程之前,两个同时运行

 

加入主线程程之后

try {
   
thread1.join();
} catch (InterruptedException e) {
   
e.printStackTrace();


类似于单线程模式,只有加入主线程的执行完才会执行后面的

 

3,是线程优先级的设置, setPriority;也就是说当线程处于竞争关系的时候,优先级高的线程会有更大的几率获得CPU资源

//最大优先级
thread1.setPriority(Thread.MIN_PRIORITY);
//设置最小
thread2.setPriority(Thread.MAX_PRIORITY);
thread1.start();
System.out.println(thread1);
thread2.start();
System.out.println(thread2);

 

结果打印,看优先级一个10一个1而且优先级为10的占用更多资源,会先被执行完…..,

 

 

4;Thread.yield()当前线程,临时暂停,使得其他线程可以有更多的机会占用CPU资源

Thread thread2 = new Thread(() ->
{
while (!four.isDead()) {
////临时暂停,使得thread1可以占用CPU资源
       Thread.yield();
       three.attackHero(four);


结果是优先级相同下,临时暂停的会让出cpu资源




又改变优先级,把暂停线程的优先级调大,然后看资源占有率,会发现,优先级会抵消部分暂停失去的资源,至于有没有平衡点就暂时不看了......


5;是守护线程;当一个进程里,所有的线程都是守护线程的时候,结束当前进程;因为类似于aop切面;守护线程通常会被用来做日志,性能统计等工作。如果其他线程都结束了,就像没有核心业务一样,也没有核心线程,那么守护线程也没什么用了, 进程就会自动结束。setDaemon

});
//只有守护线程,会直接终止进程
thread3.setDaemon(true);
thread3.start();
System.out.println(thread3);


 6;总结一下,三种方式开启多线程;线程有五种常用方法


 

,零碎的知识点


1;如果方法又异常,那么调用该方法也会抛异常


public void attackHero(Hero hero) throws InterruptedException
   
Thread.sleep(1000);
   
hero.hp -= damage;


这里调用也会抛异常


 

最直接的解决办法也是上抛….


 

 

还有一种更方便的是,前面的方法不要上抛,而是用try…catch捕捉调用的时候就不会报异常了

 

public void attackHero(Hero hero)
{
   
try {
       
Thread.sleep(1000);
   
} catch (InterruptedException e) {
       
e.printStackTrace();
   
}

 

2;格式化输出,又学到了,浮点型的小数点可控制;

System.out.format("%s正在攻击%s,%s的血变成了%.0f%n"


F前面的而数字就是保留小数……


 

 

3;匿名类关于线程的可以简写

 

而且不用声明重写方法

Thread thread3 = new Thread(() ->
   
int seconds = 0;
   
while (true) {
       
try {
           
Thread.sleep(1000);

 

 

明日计划的事情:


1;继续学习资源线程基础知识


2;完成初步压测


3;学习Java知识点



 

遇到的问题及解决方法:

 

1;小问题,老是提示,改一下


 

 

换一下驱动类….

 

 

2;切面失效了….简单试试service,结果不报错但也不运行aop方法


 

 

很简单的问题,就是根本没有扫描到aop这个切面………还是没真正掌握springspringMVC两者的区别,扫描的意义……父子关系,继承关系,子类可以用父类,子类扫描父类用不了…..加上util可以,或者直接改成扫描项目所有的……这个就算了,扫描粒度太大,不过可以作为一个检测验证,是否是扫描不到类的问题


 

 

然后是扫描controller……明白了上一个就好了,直接在MVC文件理配置好


 

 

结果可以;service里的方法,controller里都有.


 

 

 

收获:


1;初步结束线程进程概念


2;学习了匿名类的概念以及简单应用


3;完善了aop切面日志功能

 

 

 



返回列表 返回列表
评论

    分享到