JAVA进阶的基础知识快速通过---自学笔记(二)

温故而知新---陆续学习陆续更新中,你有更好的记忆和学习方法,请在评论区提出来大家一起交流,认真看完,一行行代码备注看完看懂,保证学会,学不会找我。

前言:

代码学完发现很简单,很多初学者搞不明白什么这个那个,其实是没有把概念记住,没有那么多为什么,为什么就这样做,就像小时候学数学,有很多的公式,刚开始学,我们只要死记公式,然后多练习,练习多了就不需要公式了,有时口算都能出来,到现在也不需要去理解公式为何是这样,不需要去深究它。后面你精通后在去专研它也可以。

比如在我的笔记里,里面有很多固定写法,你只需要记住就行,比如有class开头你就知道后面肯定是类对象,有new就是新建一个对象,List这样的你就知道是集合、有<>是泛型的概念等等,多多照着做,一百个人写一个相同的代码都可能有100个为什么这样写可以,这样写不可以,我能不能这样写的念头。

师傅领进门,修行看个人,同一套剑法,同一个师傅,100个学生的等级功力都不一样,更可况后面选择的职业和方向都不一样的,要想厉害就要多磨剑,多练,不然久不练剑法招式会忘光,代码页一样,你天天敲,敲个一年半载,其实来回敲的都是那些代码,换汤不换药,都一个套路,程序员你一个星期不写代码,你都不熟练甚至都不知道了,更可况你一个新入门的新手。

Java基本入门基础已经写完,现在要讲些进阶教程(标红的都是需要掌握的知识),这里让你快速复习这些进阶知识的概念,快速回忆:

  • 线程/并发(加锁、死锁)
  • 枚举
  • IO流(文件操作)
  • 集合(容器)
  • 泛型
  • 反射
  • 网络通信
  • 注解
  • JVM虚拟机(类加载)
  • 动态与函数式编程
  • 异步/同步

线程

我们原来做的都是属于单线程,就是一步步的执行,那多个线程是什么,就是说你在执行这个的时候,另个线程也在同步执行,就看谁先抢占资源。

单线程:逐行(一行行)去执行,如:先写一个类,在写一个方法,然后写内容。

程序:就是执行的代码;

进程:执行中的程序;

线程:轻量级的进程;(线程本身不能单独运行,必须放在一个进程中才能执行)

线程模型:一般是五种状态,要记住;

1.新建状态:线程被创建后处于新建状态;

2.就绪状态:(1)新建状态的线程调用start()进入就绪状态;(2)阻塞状态的线程解除之后进入就绪状态;

3.运行状态:处于就绪状态的线程获得CPU资源,该线程就进入了运行状态;

4.阻塞状态:是一个正运行的线程,因为一些原因让出CPU资源暂时中止而进入的状态;

5.终止状态:(1)正常终止;(2)强制终止,stop、destroy;(3)异常中止:当线程中产生了异常,线程终止;

一、创建线程Thread:

这个也比较简单,跟我们继承类一样,需要继承,但是继承在java只能继承一个,使用extends来继承Thread线程;

固定写法:

很明显,跟我们继承差不多,就是继承了多线程Thread类(也就是说别人写好了多线程这个类给你用)                 

class 类名 extends Thread{//Thread具有线程功能

     @Override //重写run方法
      public void run(){

      //相关代码

     }

}

例子:

如何让它具备线程功能:

步骤1.A a = new A();//要先new一个对象出来,继承的new方法:MyThread thread = new MyThread();

步骤2.A.start();//调用,对象.start();

怎么调用?写个测试类:

public static void main (Strung[] eras){

  MyThread thread = new MyThread();//步骤1:new一个thread的对象

  thread.run();//我们一般调用继承就是这么调用的,但是这样子会失去多线程的功能;要等这个执行完,才执行后面的语句;



  thread.start();//步骤2:调用方法,这才是正确调用多线程的方式,对象.start();可以先执行后面的语句,在执行这句话(谁抢占到资源就执行谁,这就是多线程的)



  system.out。ptint(“后面的语句,用来测试最后才输出还是同步输出”);
}

二、创建Runnable接口

实现起来也比较简单,接口可以实现多个,使用implements关键字来继承Runnable线程和其他;

固定写法:          

Class A implements Runnable{

    @Override //重写run方法
    public void run(){

     //相关代码
    }
}

如何给它线程的功能,怎么调用:

步骤1.A a = new A();//要先new一个对象出来,接口new对象的方法:MyThread mt = new MyThread();

步骤2.Thread t = new Thread(A);//这个才是让它具备主线程的方法

   或者 Thread t1 = new Thread(A,“线程1”);//重载方法,给这个线程取个名字(这样在执行好判断是哪个线程在执行),

步骤3.A.start();//调用,对象.start();

例子:

如何具备线程功能,如何调用,

//主线程,main函数、测试。
public static void main (Strung[] eras){
  MyThread mt = new MyThread();//步骤1.new一个对象,接口new对象的方式,实现MyThread这个类,没有实现线程功能

  Thread t = new Thread(mt);//步骤2.创建线程功能,Thread才具备线程功能,跟继承写法差不多
  t.start();//步骤3.调用线程的方法

  //主线程在执行其他代码
  for(){
    try{

      Thread.sleep(100);//休眠
    }catch(InterruptedException e){
       eprintStackTrace();
     }

  }

System.out。println(“主线程”+i);
}

三、Thread和Runnable的比较:

从表面看一个是属于继承Thread(extends Tread 这个在java中只能单继承),一个属于接口Runnable(implements Runnable这个能够实现多个接口,灵活,但是需要依赖第一种的写法),这就是继承和接口的概念;

这两个用哪个都可以;

多线程的应用(实战):

举例来讲解:

随便写两个线程,执行下,看他们能否并发执行;

先新建一个线程1:MyRunnable1,输出+号

再新建一个线程1:MyRunnable2,输出*号

写个main主函数测试方法测试一下:

输出的结果 是+和*杂乱无章,不按顺序输出,每次点输出结果都不一样,都是由计算机判断谁抢到资源谁就先输出;

根据线程的五种状态运行,很符合;

总结:java对于线程启动后唯一能保证的是每个线程都被启动并结束,但对于哪个先执行,什么时候执行,是没有保证的。

 

线程的优先级(查询or改变线程优先级)

既然输出的规则杂乱无章,没有规律可循,那么优先级是否能影响它们的输出呢?

在java中的优先级是从1-10,默认5,最高时10,最低是1;

查询优先级:对象.getprioity();

上面的例子,我们先查询它们的优先级(main函数里面写):

输出,查询出来的默认优先级都是5

我们来改变优先级(main函数里面写):

最后根据上面的例子,执行的+和*号,输出结果我们发现t1的高优先级输出的概率高,也就是t1先输出,可不是每次都这样,多运行几次,有时就先出t2优先级低的。

总结:java中优先级高的线程有更大的可能获得CPU(优先执行的概率大而已),但并不是优先级高的总是执行,也不是优先级低的不执行;

 

调度线程的三个方法(常用):

一、休眠方法sleep();

通过这个方法让线程睡一会,睡醒之后,在进入就绪状态,等等调度,休眠多久,转入毫秒,纳秒,如:sleep(毫秒数);

案例:顺序输出0~9,我们每输出一个数字就休眠1秒,即sleep(1000);每打印一个数就休息一秒

二、暂停方法yield();

这个暂停方法是用于释放资源的;

案例:有两个线程a和b,假如a先获得资源,a先执行,a执行完后,就释放资源a.yield,这是a就释放资源给大家抢(注意:这里有个坑:a其实也假如抢资源,它自己释放,它自己也可以抢,有可能也被a再次抢到资源,记住这个知识点),也就是说,当a释放资源后,a、b两个加入随机抢资源的

案例:创建两个资源线程试试

先写第一个资源线程试试(用接口和继承都可以),线程1 MyRunnable1,(a线程),输出200个+号,然后释放资源Thread.yield();

在写第二个线程2 MyRunnable2(与线程1差不多,名字不一样而已,b线程),输出200个*号,

最后写个main主函数,测试类试试:

输出结果:输出线程1和线程2的+和*号是随机出现的,因为线程1和线程2的资源释放后也再次参与抢,一起竞争;

有些资料这么理解,是错误的理解,误人子弟,他们认为输出结果是++++++******,这样交替输出的,这是因为他们理解释放完后其他线程去抢,所以是交替的。---大家要注意这个坑

这个方法会经常被误用,所以用的时候要小心;

 

三、挂起方法join();

这个方法是用于插队的,让线程插队先执行;

案例:

也是写两个线程输出+和*号,这里略,可以参考上面的,不重要,理解就行;

直接写main主函数测试:

这里解释下,我们在第五行的时候i==5输出+号(就是第五行的时候强行插入*号),即mt.join();的用法;

线程同步

问题的由来(为何需要同步方法):

说到同步,我们先来说个例子,在办公室只有一台打印机、有几个人需要打印(如图),这种情况我们知道是多线程状态,无论哪个人先抢到资源,我们知道线程中,执行的线程都是随机的,会出现各种意想不到的情况,无法决定线程的输出顺序。比如:老王先抢到资源,但是他没有打印完30页,资源又被老李抢去了,就打印老李的,然后又随机,可想而知,打印机打印出来的内容都是穿插每个人的内容,还要挑出来多麻烦。

我们能不能这样,谁先抢到资源,然后先执行完他的,在执行第二个抢到资源的那位,比如:老王先抢到资源,打印机把老王的30页先打印出来先,然后再释放给下一位,如老李抢到第二个资源,就接着打印20页完....这样的场景才是真实的场景。

 

代码例子:

1.先新建一个打印机类,具备打印机功能print类

Thread.sleep();加这个是为了被打印那么快,为了看看效果而已。

2.在写人,如老王、老李的类具有线程功能,因为模拟抢占打印机(报错是里面没有好有重写run方法,写进去就可以 ,然后快捷键出属性的构造方法)

最后写个main方法测试下:

这就是几个人同时用打印机,打印出来时这样的结果,不符合实际运用,我们下节课讲到锁;

这就是我们今天讲的同步资源,我们可以采取加锁(Synchronized)的概念,老王先抢到资源,那我就先给老王加锁,等老王打印完后再释放,以此类推!

解决方法:加锁(Synchronized)---就是同步方法

为什么需要同步,如:小明、小红打印出来的都是随机的,应该是一个人打印完,在打另一个人的。

 

固定写法(两种方法):

  1. 同步方法:在方法中加锁,当线程同步的时候,会获得同步方法所属对象的锁,一旦获得对象的锁,则其他线程不能再执行被锁对象的其他同步方法。只有在同步方法执行完毕后释放了锁,其他线程才能执行。

例如:老王先抢到资源,给老王加了锁,其他人就不能抢资源了,等老王打印后,释放锁释放资源,第二个老李抢到,又给老李加锁,老李才执行第二个人得打印工作,以此类推!                            

Synchronized 方法声明{



}

2.同步块方法:同步块是在run方法中加锁。

//同步块是在run方法中加锁

Synchronized(资源对象){//相当于单线程了,资源对象时哪个需要资源,如老王还是老李

   //需要进行同步的方法

}

例:还是上面的案例:在run()方法中加锁

结果:输出的结果很明显,先打印完一个人得,在执行另一个人得

同步方法加锁和同步块加锁,同步方法是在类对象中加锁,这个加锁代表类对象里的都已经都加了锁,同步块加锁是锁住资源对象。

写两个类对象method1()和method2()加锁试试,这里就不试了,理解就行。

死锁

有了锁的概念,我们会出现什么问题呢?比如:a和b线程,a持有锁A,在等待锁B,而b持有锁B,在等待锁A,这样a和b陷入了等待,谁都不获得资源就不释放,两者就这么僵持下去,最后谁都不执行。这就是死锁的概念。

也就是,你不给我资源A,我就不给你资源B,两个对持。最好是一手交钱一手交货才好。

代码例子就省略了,理解这个意思就行,当你给资源加锁,发现不执行,那么就是进入了死锁里了。

看下面的输出,线程123都相互在等待资源,而这些资源也都没有被释放,就这么等下去了,右上角红色图标说明程序还在执行当中,没有结束,这样就是进了死锁里面了。

生产者/消费者设计模式

生产者生成东西放仓库,消费者从仓库中取,生产仓库满了,生产者就不生产了,消费者取仓库空了,就不取了。生产者每生产东西就通知消费者,消费取东西也会通知生产者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

测试狂人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值