Java线程相关概念


要想明白线程的概念,我们要先搞清楚进程的概念

进程

进程的概念

为了使参与并发执行的每个程序都能独立运行,在操作系统中必须为止分配一个专门的数据结构,就叫做进程。
进程是指运行中的程序,比如说我们在电脑上玩LOL,就启动了一个进程,操作系统就会为该进程分配内存空间

进程的特征

1.动态性:进程有自身的产生,存在和消亡过程
2.并发性:是指多个进程一起存在于内存中,且能够在一段时间内同时运行,引入进程的目的也是为了使一个进程能与其他进程同时执行
3.独立性:进程是一个能独立运行,独立获取资源和独立接受调度的基本单位
4.异步性:进程按异步方式运行的,即按各自独立的、不可预知的速度运行

线程

线程的概念

1.线程由进程创建的,是进程的一个实体
2.一个进程可以有多个线程,如下图所示。
在这里插入图片描述
可以理解为一个浏览器是一个进程,而每个网页就是一个线程。

线程其他相关的概念

单线程

同一个时刻,只允许执行一个线程

多线程

同一个时刻,可以执行多个线程,比如:一个qq进程,可以同时打开多个聊天窗口。

并发

同一个时刻,多个任务交替执行,造成一种“同时执行”的错觉,简单的说,单核cpu实现的多任务就是并发。

并行

同一个时刻,多个任务同时执行。多核cpu可以实现并行。比如说在电脑上我可以边听音乐边打游戏。

Java中创建线程的两种方式

继承Thread类,重写run方法

下面我们给出一道题来引出线程
在控制台每隔一秒钟输入一个数字,输出1-10。

public static void main(String[] args)  {
        Cat cat = new Cat();
        cat.start();//cat.start()是开始执行线程
    }

class Cat extends Thread{
    int count = 0;
    @Override
    public void run() {
        while (true){
            System.out.println("子线程执行"+ ++count+"次");
            try {
                Thread.sleep(1000);//Thread.sleep()是休眠的意思,这里的1000单位是ms                
                //意思是每执行一次线程,需要休眠1秒后再开始执行
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(count == 10){//当count=10时,就会终止线程
                System.out.println("子线程结束");
                break;
            }

        }
    }
}    

实现Runnable接口,重写run方法

 public static void main(String[] args)  {
        Cat cat = new Cat();
        Thread thread = new Thread(cat);
        thread.start();
    }

class Cat implements Runnable{
    int count = 0;
    @Override
    public void run() {
        while (true){
            System.out.println("子线程执行"+ ++count+"次");
            try {
                Thread.sleep(1000);//Thread.sleep()是休眠的意思,这里的1000单位是ms                
                //意思是每执行一次线程,需要休眠1秒后再开始执行
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(count == 10){//当count=10时,就会终止线程
                System.out.println("子线程结束");
                break;
            }

        }
    }
}    

Java中线程的相关方法

setName和getName

setName: 设置线程名称
getName: 返回该线程的名称

public static void main(String[] args)  {
        Cat cat = new Cat();
        Cat cat1 = new Cat();
        Cat cat2 = new Cat();
        System.out.println(cat.getName());
        System.out.println(cat1.getName());
        System.out.println(cat2.getName());

    }

在这里插入图片描述
可以看到,我们用getName方法获得了线程的名称

 public static void main(String[] args)  {
        Cat cat = new Cat();
        Cat cat1 = new Cat();
        Cat cat2 = new Cat();
        cat2.setName("线程2");
        System.out.println(cat.getName());
        System.out.println(cat1.getName());
        System.out.println(cat2.getName());

    }

在这里插入图片描述

可以看到,我们用setName方法将Thread-2的名称改为了线程2

start和run

run调用线程对象run方法
start使该线程开始执行;
start底层会创建新的线程,调用run, run 就是一个简单的方法调用,不会启动新线程。
Java虚拟机底层调用该线程的start0方法,start0方法又调用了run方法

public synchronized void start() {
       /**
        * This method is not invoked for the main method thread or "system"
        * group threads created/set up by the VM. Any new functionality added
        * to this method in the future may have to also be added to the VM.
        *
        * A zero status value corresponds to state "NEW".
        */
       if (threadStatus != 0)
           throw new IllegalThreadStateException();

       /* Notify the group that this thread is about to be started
        * so that it can be added to the group's list of threads
        * and the group's unstarted count can be decremented. */
       group.add(this);

       boolean started = false;
       try {
           start0();
           started = true;
       } finally {
           try {
               if (!started) {
                   group.threadStartFailed(this);
               }
           } catch (Throwable ignore) {
               /* do nothing. If start0 threw a Throwable then
                 it will be passed up the call stack */
           }
       }
   }
   
private native void start0();

   /**
    * If this thread was constructed using a separate
    * <code>Runnable</code> run object, then that
    * <code>Runnable</code> object's <code>run</code> method is called;
    * otherwise, this method does nothing and returns.
    * <p>
    * Subclasses of <code>Thread</code> should override this method.
    *
    * @see     #start()
    * @see     #stop()
    * @see     #Thread(ThreadGroup, Runnable, String)
    */
   @Override
   public void run() {
       if (target != null) {
           target.run();
       }
   }

start()方法调用start0()方法后,该线程并不一定会立马执行,只是将线程变成了可运行状态。具体什么时候执行,取决于CPU,由CPU统一调度。

setPriority和 getPriority

高优先级的线程比低优先级的线程有更高的几率得到执行,实际上这和CPU的调度有关,有可能设置了优先级也不会出现想要的结果。
线程优先级范围[1-10]。
setPriority:更改线程的优先级
getPriority:获取线程的优先级

   public static void main(String[] args)  {
        Cat cat = new Cat();
        Cat cat1 = new Cat();
        System.out.println(cat.getPriority());
        System.out.println(cat1.getPriority())
    }

在这里插入图片描述
用getPriority方法获得了线程的优先级

 public static void main(String[] args)  {
        Cat cat = new Cat();
        Cat cat1 = new Cat();
        cat.setPriority(9);
        System.out.println(cat.getPriority());
        System.out.println(cat1.getPriority());
    }

在这里插入图片描述

用setPriority方法将线程cat的优先级改为了9

sleep和interrupt

sleep: 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
interrupt:中断线程,但并没有真正的结束线程。一般用于中断正在休眠线程。

public static void main(String[] args) throws InterruptedException {
        Cat cat = new Cat();
        cat.setName("子线程");
        cat.start();
        for (int i = 0; i < 3; i++) {
            Thread.sleep(1000);//休眠1000ms
            System.out.println("主线程"+i);
        }
        cat.interrupt();
    }

class Cat extends Thread{

    @Override
 public void run() {
        while (true){
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName()+i");
            }
            try {
                System.out.println(Thread.currentThread().getName()+"休眠中");
                Thread.sleep(30000);//休眠30000ms
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName()+
                "被interrupt了");
            }
        }
    }
}

在这里插入图片描述

可以看到主方法中,先是创建了一个cat线程,然后让cat线程开始执行(cat.start())。
在线程类Cat中的run方法重写了。
先打印子线程0-子线程2,然后调用sleep方法使该线程休眠30s
按道理来说应该等待30秒后又会重新开始打印子线程0-子线程2
即38s才开始打印子线程0-子线程2
但是实际上是第9秒钟线程又恢复了打印。
这是因为当主线程打印完了主线程0-主线程2后,调用了cat.interrupt,该方法会中断正在休眠线程。

join

join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务。

public static void main(String[] args) {
        int count = 0;
        T t = new T();
        Thread thread = new Thread(t);
        thread.start();
        for (int i = 1; i <= 5; i++) {
   System.out.println(Thread.currentThread().getName()+ "小弟吃"+ ++count +"包子");
            try {
                Thread.sleep(1000);
                if(count == 2){
                    System.out.println("小弟让大哥先吃");
                    thread.join();//当小弟吃到第二个包子时让大哥先吃
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
  class T implements   Runnable{
    int count = 0;
    @Override
    public void run() {
       while (true){
    System.out.println(Thread.currentThread().getName()+"大哥吃"+ ++count +"包子");
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           if (count == 5){
               break;
           }
       }
    }
}

在这里插入图片描述
该程序一开始是主线程和子线程一起运行即大哥(子线程)和小弟(主线程)一起吃包子
当小弟(主线程)吃到第二个包子时(count == 2)时,小弟让大哥先吃(thread.join),大哥(子线程)插队。
当大哥(子线程)吃完5个包子(count == 5时),子线程退出。
然后小弟再吃(主线程再执行)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值