栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程(二)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程(二)

一、线程之间的数据共享—线程通信

大部分场景下,几个线程之间是需要协调配合工作(线程之间需要进行数据交换),一起完成一个总目标的。由于我们的线程都属于同一个进程,所以共享有OS分配过来的同样的资源(其中优先关注内存资源)

1.JVM下的内存区域划分

PC保存区(PC);栈区(本地方法栈;虚拟机栈);堆;方法区;运行时常量池

      这些内存资源是属于进程的。理论上来讲,确实也是这个进程下所有线程的,但在进程内部也有分配机制,这些内存在线程中还会分配一次。(类比:家庭财务,属于家庭,但细分每个人都有对应花销)并且不是操作系统做分配了,是进程内部分配。

      堆、方法区、运行时常量池是整个进程(JVM)只有一份,PC(保存PC值)、栈(虚拟机栈、本地方法栈)是每个线程独一份(各自有各自的)【对象是共有的,加载的类是共有的】

1)为什么每个线程要有自己的PC

每个线程都是独立的执行流,要下一条要执行的指令和其他线程无关,所以有自己的PC。

2)为什么每个线程都得有自己的栈

每个线程都是独立的执行流,各自有各自调用的方法链,有各自要处理的临时数据,所以栈也是独一份的。

3)体现到代码中的共有和私有

局部变量,保存在栈桢中,也就是保存在栈中,是线程私有

类对象(Class对象-关于类的对象)、静态属性,保存在方法区中,所以是线程之间共享的【前提:有访问权限】

对象(对象内部属性),保存在堆中,所以是线程之间是可以共享的【前提:线程持有该对象的引用】(见4)5)这个两个例子)

1)区分不同内存块的r

public class Main {
    static class MyThread extends Thread{
        @Override
        public void run() {
            int r=0;//r存在于子线程run方法的栈帧中
            for (int i=0;i<1000;i++){
                r++;
            }
            System.out.println(Thread.currentThread().getName()+":"+r);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        int r=0;//r存在于主线程main的栈帧中
        MyThread t=new MyThread();
        t.start();//开启线程
        t.join();//等待线程结束
        System.out.println(r);//此处r仍为0,因为++的是子线程的r,不是主线程的
    }
}

2)一共在内存中开辟了几个名叫r的内存块

public class Main {
    static class MyThread extends Thread{
        private final int total;
        public MyThread(int total){
            this.total=total;
        }
        @Override
        public void run() {
            int r=0;//r存在于子线程run方法的栈帧中
            for (int i=0;i<1000;i++){
                r++;
            }
            System.out.println(Thread.currentThread().getName()+":"+r);
        }
    }

    
    public static void main(String[] args) throws InterruptedException {
        int r=0;//r存在于主线程main的栈帧中
        MyThread t1=new MyThread(1000);
        t1.start();//开启线程
        MyThread t2=new MyThread(1000);
        t2.start();//开启线程
        MyThread t3=new MyThread(1000);
        t3.start();//开启线程
        t1.join();//
        t2.join();//等待线程结束
        t3.join();//等待线程结束
        System.out.println(r);//此处r仍为0,因为++的是子线程调用到的r,不是主线程的
    }
}

结果:

Thread-0:1000
Thread-2:1000
Thread-1:1000
0

3)r为静态属性时,整个进程中就这一个r

public class Main {
    static int r=0;//定义为静态属性
    //进程中就这一个r
    static class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                r++;
            }
            System.out.println(getName()+":"+r);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread t=new MyThread();
        t.start();
        t.join();
        System.out.println(Thread.currentThread().getName()+":"+r);
    }
}

结果:

Thread-0:1000
main:1000

分析:主线程虽然不对r做更改,但是子线程改变了r的值,主线程也就同步更改了,这也就是数据共享。

4)对象没有共享的情况

public class Main {
   static class SomeObject{
       int r=0;
   }
    static class MyThread extends Thread{
        @Override
        public void run() {
            SomeObject someObject=new SomeObject();
            for (int i = 0; i < 1000; i++) {
                someObject.r++;
            }
            System.out.println(getName()+":"+someObject.r);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SomeObject someObject=new SomeObject();
        MyThread t=new MyThread();
        t.start();
        t.join();
        System.out.println(Thread.currentThread().getName()+":"+someObject.r);
    }
}
//结果:
//Thread-0:1000
//main:0

5)对象之间共享的情况-操作的是同一批数据

package com.wy.about_data_share.demo5;
//想办法让子线程和主线程的引用指向同一个对象-利用构造方法
public class Main {
   static class SomeObject{
       int r=0;
   }
    static class MyThread extends Thread{
       private final SomeObject someObject;
       public MyThread(SomeObject someObject){
           this.someObject=someObject;//这个someObject指向主线程main方法栈的someObject指向的对象
       }
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                someObject.r++;
            }
            System.out.println(getName()+":"+someObject.r);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SomeObject someObject=new SomeObject();//只有这个地方创建对象
        MyThread t=new MyThread(someObject);//把SomeObject对象的引用传入
        t.start();
        t.join();
        System.out.println(Thread.currentThread().getName()+":"+someObject.r);
    }
}

结果:

Thread-0:1000
main:1000

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/821550.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号