Java多线程学习记录

Java多线程

简介:Java 多线程是 Java 面试中必考的一个点,多线程在Java程序中扮演了一个很重要的角色,因此我们有必要去深入的了解 Java 的多线程

下面进入Java多线程的学习

多线程的概念

在了解什么是多线程之前,我们必须要理解什么是进程。而进程呢,就是我们调试程序的过程。怎么说呢,其实就是将程序运行起来,到最后你不想它运行了把它关闭了的这么一个过程。在这个过程里计算机会经历从代码加载到内存,代码执行和执行完毕,程序退出,内存空间被销毁。这个整体的状态,称之为程序的进程。而其中,代码按照顺序不断执行的过程,而这样就形成一个线程

多线程呢,简单来说就是让多个线程去完成一个大项目,其中每个单线程之间互不干扰,以此来提升程序运行的速率。

为什么要多线程

其实原因很简单,我们的程序运行的时候是按照代码顺序一步一步去执行的,这样看起来不存在什么问题,但是在实际生活中问题就很大。这里我用一个我从网上看到的例子来进行解释:假设我们的用户(就叫小J同学吧)要从网上加载一张比较大的图片(极高像素的可能会有几个G那么大)到手机上并且显示它,会是怎么样的呢?(就假设是这张吧,手动滑稽)在这里插入图片描述我们首先从单线程的角度去分析它,但我们要加载图片的时候,肯定要等它加载完了以后才能进行下一步操作是吧,问题就在这里,如果我们的超高清的图要加载一个小时呢?在这个过程中小J同学可不能执行其它操作,就只能眼巴巴的看着等程序加载完,但小J同学会这样等吗?等,这辈子都不可能等的。我们只会看到小J同学默默的将我们的软件移除他的手机,并反手个我们一个赞。 所以我们必须要想一个办法,既要让小J同学最终等到这张图片,同时也不用说只能等待什么也干不了。 而这时,我们的多线程技术就排上用场了,我们创建多个线程来加入我们的程序,你可以理解为我们创建了好几个工人,他们各自负责一些指定的内容,而不是只有一个工人来干完一件又一件的事情。而这样我们的小J同学就能在(打打游戏,看看视频)中“等”到这张图片了。到了这里你就应该明白多线程了,所谓多线程,就是指可以同时运行多个程序块,是程序运行的速率更高

OK,理解了多线程之后,我们就该去实现多线程了

要实现多线程,从整体上而言,主要分为两种方式,分别是继承Thread类或者实现Runnable接口,下面我们就一起去看看相对更加详细的介绍吧

一、继承Thread类

Thread类存放在 java.lang 包中,当一个子类继承了Thread类时,必须实现其自带的 run() 方法,在编写中需要实现的功能代码,然后创建出该对象,调用 start() 方法执行。格式如下:

class ClassName extends Thread{
 public void run(){
	 //代码
 	}
}
ClassName test = new ClassName();
test.start();

实例测试:

package test;

class Threadtest1 extends Thread{
 public void run() {
  for(int i = 0;i<5;i++) {
   System.out.println("测试线程1--->"+i);
   
  }
 }
}
class Threadtest2 extends Thread{
 public void run() {
  for(int i = 0;i<5;i++) {
   System.out.println("测试线程2--->"+i);
   
  }
 }
}
public class MyThread{
 public static void main(String[] args) {
  Threadtest1 test1 = new Threadtest1();
  Threadtest2 test2 = new Threadtest2();
  test1.start();
  test2.start();  
 } 
}

运行结果:
在这里插入图片描述
在这里,我们发现,尽管test1和test2打印的代码的顺序并不是连续的,但是也还是一个一个地打印出来,按道理来说,那也还是顺序执行是吧?是的,在我们的多线程中,程序的执行也是有顺序的,那么什么才是决定顺序的标志呢?就是CPU资源,我们的CPU在程序运行的时候会产生空闲的CPU资源,一旦哪个线程抢先获得了这个资源,就可以执行它的代码。所以,在多线程中,抢资源是非常关键的,这也说明了为什么运行结果会有线程1和线程2交互执行。当然,如果我们再次执行的时候,就会发现,其实他的结果也是会发生变化。因为每一次执行的时候,我们都不知道哪个线程会先取得CPU资源,所以每一次的运行结果都是未知的。但不可否认的是,这样的话,真的实现了我们一边加载图片,一边执行其他操作的愿景。当然,问题也会产生,聪明的我们即将一步一步探究怎么解决这些问题。慢慢来,不要急。
【注意:一个线程对象只能调用一次start方法,如果重复调用会报IllegalThreadStateException异常】

二、实现Runnable接口

其实Thread是直接继承自一个Runnable的接口来实现多线程的(有兴趣可以去看一下Thread的源码)因此我们既然可以用Thread来实现多线程自然也可以用Runnable来实现,OK,下面我们来看一下基本格式:

class className implements Runnable{
 public void run(){
 	 //代码
 	}
}

下面是实例测试:

package test;

class Threadtest1 implements Runnable{
    public void run() {
        for (int i = 0;i<9;i++) {
            System.out.println("thread1->"+i);
        }
    }
}
class Threadtest2 implements Runnable{

    public void run() {
        for (int i = 0;i<9;i++) {
            System.out.println("thread2->"+i);
        }
    }
}

public class MyThread{
	public static void main(String[] args) {
		new Thread(new Threadtest1()).start();
		new Thread(new Threadtest2()).start();
	}	
}

在这里插入图片描述
在这里,我们是通过匿名内部类来实现了一个Thread对象,并且调用了这个对象的start方法。但是这个对象呢,和我们在上面看到的Thread又有点区别,就是他不需要重写run方法,而把这个run方法的实现交给了Runnable。就好比Thread是一把枪,Runnable是炮弹。即便我们是在Thread内部重写的run方法,本质上也还是Runnable,因为Thread实现了Runnable接口。所以,姑且可以理解为:Runnable是基础,Thread是拓展。而由此便引发了这两者的一个区别所在:
如果一个类继承自Thread,则不适合多个线程共享资源,而如果一个类实现了Runnable接口,则可以在多个线程中去使用,从而实现了共享资源
就好比你有一支可以自动产生炮弹的枪,你可以随时打出这一发子弹,但是你不能做到把这发子弹放在其他的枪上使用。而我用工厂制作出来的标准子弹,因为没有限制在你的枪上,所以可以随便给其他的枪使用。所以,实现Runnable接口的好处就在于:

1.适合多个执行相同代码的线程去处理统一资源
2.避免由于java的单继承特性带来的局限
3.代码与数据独立分开,增强程序健壮性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值