ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

进程线程并发并行

2022-03-27 12:02:34  阅读:161  来源: 互联网

标签:run Thread 代码 并行 Cat 并发 线程 public


进程

1.进程是指一个进行中的程序或者一次程序的一次执行过程,是个动态过程,进程有自己的产生,存在和消亡的过程

 

2.不同的进程可以是同一个软件,比如打开了10个腾讯QQ,那就是10个进程

 

 

 

线程

1.一个线程是进程创建出来的一个实体,一个进程可以有多个线程

 

2.同一时刻,只允许执行一个线程的叫单线程,而可以执行多个线程的叫做多线程

 

3.一个逻辑处理器会处理一个线程

 

 

线程的使用

(1)创建类继承Thread类(此类实现了Runnable接口),重写Run(),此时一个类可以当作一个线程来使用

(2)创建类去实现Runnable接口,重写Run()

 

public class Test1 {
    public static void main(String[] args) {
        new Cat().start();
//start方法可以帮你直接运行run方法 } }
//可以选择实现Runnable接口,也可以选择继承Thread类 class Cat extends Thread{ @Override public void run() { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("柴郡:喵喵喵!"); } } }

 

当run方法结束后,线程也挂掉了,当所有线程挂掉时,进程随即挂掉

 

 

 

但上面这个继承Thread类的线程,很多时会遇到一个很矛盾的问题:java只能单继承,所以如果这个类要继承其他的类,那就不能去继承Thread类了,所以其实第二种方法会更适用,我们来使用一下第二种方式

先看这段代码

public class Test1 {
    public static void main(String[] args) {
        //因为start方法时在Thread里面的,
        //所以要创建一个Thread对象,将Cat放进去,才能启动Cat线程
     //这里Thread源码里时使用代理模式来给Cat开一个线程 Thread thread = new Thread(new Cat()); System.out.println("主线程"); } } class Cat implements Runnable { @Override public void run() { System.out.println("子线程" + "线程名字:" + Thread.currentThread().getName()); } }

运行结果

 

 

 

 

 

 

 

 

 

多线程机制

当一个线程A使用方法开启了另一个线程B时,称A为是B的主线程,B是A的子线程,比如上面的main线程就是Cat的主线程,

然后B线程同样也可以再开启其他线程,A线程也可以再开除了B线程以外的线程,如下图

 

 

那么既然主线程和子线程在产生上有关系,那么运行时,它们之间会有什么关系吗?我们用代码来验证

public class Test1 {
    public static void main(String[] args) {
        new Cat().start();

        for (int i = 0; i <= 60;i++) {
            System.out.println("主线程");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

class Cat extends Thread{
    @Override
    public void run() {
        super.run();
        for (int i = 0;i <= 80;i++) {
            System.out.println("子线程");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果

 

可以看到,每次都会一并输出主线程和子线程(用Thread.currentThread().getName()可以看到子线程的名字是Thread-0),这意味着,main线程和Cat线程不会造成阻塞,两个线程可以同时进行,打开Jconsole可以看到如下情况

 

当一个线程时结束时,立马就会在线程列表里消失,比如下面main线程结束后就立刻从列表消失

 

 

而且注意,例子这里如果子线程也结束了, Thread-0不会从列表消失

 

这又是怎么回事?不是说一个线程结束后就会挂掉吗?

其实这是因为这里Thread-0挂掉后,整个进程就挂掉了,因为main和Cat线程都执行完了,所以这里Jconsole将会与这个进程断开连接,不会再更新这个线程列表,自然就会留着Thread-0在那里了,稍等一会,这个Jconsol就会弹出提示了

 

 

 

但是,我们又有一个疑问:在主方法里直接创建Cat的对象来调用run方法也能执行run的方法体,这和用start来执行会不一样呢?让我们来改改上面代码,看看输出结果

 

public class Test1 {
    public static void main(String[] args) {
        new Cat().run();
        System.out.println("主线程");
    }
}

class Cat extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("子线程" + "线程名字:" + Thread.currentThread().getName());
    }
}

运行结果

 

可以看到,如果是直接调用run方法,Cat线程将不会被启动,run方法将会串行化在main线程,按照代码顺序,执行到run方法时,会先执行完run方法,才会继续执行下一条语句,这就导致了main线程的停滞,所以start方法可以让线程之间不造成阻碍,各自通畅运行

 

那么start()又是怎么去启动线程呢?我们瞜一眼它的源码,引入眼帘的是它的文档说明,然后发现它调用了一个关键方法

 

 

 

可以发现当start方法执行后,JVM会调用run方法,而这个start0是一个本地方法,并且它也是JVM调用的,如下图

 

所以可以发现,start方法只是个中介,让线程能够开始运行的是start0()方法

 

 

线程的状态

 

 

 

 线程同步机制

在多线程编程时,一些数据不能被多个线程同时访问时,我们就会用到线程同步来做到:同一时刻,最多只有一个线程访问,以保证操作后的数据的正确性,也就是说,线程同步,可以保证在某一个线程A对一块内存进行操作时,其他线程不能同时掺和进来操作这块内存,必须要等线程A操作完后,才轮到下一个线程

 

想做到线程同步有多种方法,其中常用又简单的是用synchronized关键字,其同步方法时工作原理大致如下

 

除了同步方法,synchronized还可以同步代码块,格式如下

synchronized(对象){

//需要被同步的代码

}

 

总之,synchronized关键字最主要有以下3种应用方式


(1) 修饰实例方法,作用于当前实例,给当前实例加锁,进入同步代码前要获得当前实例的锁

(2)修饰静态方法,作用于当前类对象,给当前类对象加锁,进入同步代码前要获得当前类对象的锁

(3)修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

 

 sychronized会给对象加互斥锁

什么是互斥锁呢?

每个对象都会对应于一个称为互斥锁的标记(用数值来标记),互斥锁的标记用来保证在同一时刻,只能有一个线程访问该对象

 

①由于一次只能一个线程,所以程序的执行效率降低是必然的

 

②静态的同步方法的锁是类本身(当前类.class),非静态的同步方法的锁是this

 

 

线程的死锁

 死锁是指两个或多个线程之间互相占用了对方的资源,导致这些线程都进入等待状态,无法执行。当线程A进入了synchronized代码块里,获得了对象的锁,导致其他线程无法进入这里,如果个线程进入的代码块,里面又有synchronized代码块C,而这个内部的synchronized代码块D是被另一个线程B占用的,并且想要线程B退出代码块D的话,线程B需要去执行完代码块C,那么问题就来了:代码块C现在是A占用,可是要A退出又需要执行完代码块D,即需要B退出代码块D,但是B要退出代码块D,又需要A退出代码块C,这样就像一个病人,需要钱才能买健康,可是同时,只有健康才能赚到钱,这就很矛盾了,简单来说就是下图

 

再用代码该感受下

public class Test1 {
    public static void main(String[] args) {
        new Cat(true).start();
        new Cat(false).start();
        //第一个cat对象想线程执行下去,需要进到加cat2锁的代码块
        //可同时加cat2锁的代码块又被第二个cat对象占用,
        //并且想让第二个cat对象退出加cat2锁的代码块,
        //又需要第一个cat对象先执行完,释放出加cat1锁的代码块
        //于是两个进程就僵持在这里了,程序一直停在这里
    }
}

class Cat extends Thread {
    static Cat cat1 = new Cat();
    static Cat cat2 = new Cat();
    private boolean loop = true;

    public Cat() {
    }

    public Cat(boolean loop) {
        this.loop = loop;
    }

    @Override
    public  void run() {
       if(loop){
           synchronized (cat1){
               System.out.println("1");
               synchronized (cat2){
                   System.out.println("2");
               }
           }
       }else {
           synchronized (cat2){
               System.out.println("3");
               synchronized (cat1){
                   System.out.println("4");
               }
           }
       }
    }
}

 

运行结果

 

 

 释放锁

下面的情况,会进行释放锁

1.当前线程的同步代码块,同步方法执行结束

 

2.当前线程的同步代码块,同步方法执行时遇到错误或异常,导致执行结束

 

3.当前线程的同步代码块,同步方法执行时,执行到了当前线程访问对象的wait方法,暂停该线程,并释放锁,但是注意,只是暂停,不是结束

 

 

以下情况,不会释放锁

 1.当前线程的同步代码块,同步方法执行时,程序调用Thread.yield,Thread.sleep方法时,只是暂停线程,不释放锁

 

2.当前线程的同步代码块执行时,其他线程调用了当前线程的suspend方法将当前线程挂起,此时不释放锁

ps:suspend方法和resume方法(恢复挂起的线程)已经过时,不推荐使用

 

 

 

 

并发

1.并发是指:同一时刻,多个任务交替执行,造成一种“同时进行”的假象,实际是只是cpu来回切换执行任务的速度快。举个例子,单核cpu的实现的多任务就是并发

 

 

 

 

并行

1.并行是指:同一时刻。多个任务同时执行。多核cpu实现的多任务就是并行,而且并发并行可以共存,比如2核cpu实现四个任务,这样每次执行两个任务,是并行,切换到另外两个任务,是并发,也就是并发和并行都出现了

标签:run,Thread,代码,并行,Cat,并发,线程,public
来源: https://www.cnblogs.com/codemelo/p/16057700.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有