Java中的多线程与同步

一、进程与线程

         进程是可并发执行的程序在一个数据集上的一次执行过程,它是系统进行资源分配的基本单位。
         线程为进程所有,作为调度执行的基本单位,一个进程可以有一个或多个线程,他们共享所属进程所拥有的资源。

二、为什么要引入进程与线程

         要探索这个问题答案之前,需要先了解并发执行。并发执行是为了增强计算机系统的处理能力和提高资源利用率,而采取的一种可以同时操作的技术,它可以被总结为:一组在逻辑上互相独立的程序或程序段在执行过程中其执行时间在客观上互相重叠。然而实际上并没有真正的同时执行,因为CPU并不能同时执行多条指令。
         由于并发执行的间断性、失去封闭性以及不可再现性,因此引入了进程,以便从变化的角度、动态的分析研究程序的并发执行过程。
         20世纪80年代中期,人们不满足与以进程为单位去解决竞争处理器的问题,所以提出了比进程更小的、能独立运行的基本单位:线程,线程可以进一步提高程序并发执行的程度,降低并发执行的时空开销。将之前进程的功能进行分离,即将资源申请与调度执行分开。所以就有了上述中进程与线程的描述。

三、Java中的进程

       当通过java命令运行一个Java程序时,就启动了一个Java虚拟机进程,Java虚拟机进程从启动到终止的过程,成为Java虚拟机的生命周期。当程序正常执行结束、程序在执行中因为出现异常或错误而异常终止、程序执行System.exit()方法以及由于操作系统出现错误而导致Java虚拟机进程终止时, Java虚拟机将结束生命周期。
       当Java虚拟机处于生命周期中时,它的总任务就是运行Java程序,Java程序从开始到终止的过程为程序的生命周期,它和Java虚拟机的生命周期一致。
       

四、Java线程的运行机制

        每当用java命令启动一个Java虚拟机进程时,Java虚拟机都会创建一个主线程,该线程从程序入口main()方法开始执行。在Java虚拟机进程中,执行程序代码的任务是由线程来完成的,每个线程都有一个独立的程序计数器(PC寄存器)和方法调用栈(method invocation stack)。

  •        程序计数器:当线程执行下一个方法时,程序计数器指向方法区中下一条要执行的字节码指令。
  •        方法调用栈:简称方法栈,用来跟踪线程运行中一系列的方法调用过程,栈中的元素成为栈帧。每当线程调用一个方法的时候,就会向方法栈压入一个新帧。帧用来存储方法的参数、局部变量和运算过程中的临时数据。
          栈帧由以下三个部分组成:
  •        局部变量区:存放局部变量和方法参数
  •        操作数栈:是线程的工作区,用来存放运算过程中生成的临时数据。
  •         栈数据区:为线程执行指令提供相关的信息,包括如何定位到位于堆区和方法区的特定数据,以及如何正常退出方法或者异常终端方法。
public class Sample{
	private int a = 0;
	public int method(){
                int b;
		a++;
		return a;
	}
	
    public static void main(String args[]){
		Sample s =new Sample();
	        s.method();
                System.out.println(a);
    }
}

    以上面为例,简单介绍线程的运行过程:
        当用java命令运行以上程序时,首先会启动一个Java虚拟机进程,然后java虚拟机进程会创建一个主线程,主线程有它自己一个独立的程序计数器和方法调用栈。
       该线程从main()方法开始运行,由方法调用栈的原理可知,首先会将main()方法的栈帧压入方法栈,其中main()方法的栈帧中存储了main()方法的参数、局部变量和运算过程中的临时数据等,main()方法栈帧中的以上这些信息分别对应存放在局部变量区、操作数栈以及栈数据区。method()方法同理。
       当该主线程开始执行method()方法的的"a++"操作时,主线程能根据method()方法的栈帧的栈数据区中的有关信息,正确定位到堆区的Sample对象的实例变量a,并把它的值加1.当method()方法执行完毕后,它的栈帧就会从方法栈中弹出,它的局部变量b结束生命周期。main()方法的栈帧成为当前帧,主线程继续执行main()方法。
        

五、Java线程的创建和启动

        

创建线程有两种方式:

 1   扩展java.lang.Thread

 2   实现Runnable接口

 

1. 扩展java.lang.Thread类方式

   Thread类代表线程类,它主要有两个方法:

    Run() --- 线程运行时所执行的代码

    Start()--- 用于启动线程

   用户的线程类只需要继承Thread类,重写run()方法,将该线程所要执行的代码放入run()方法中。

   举例1:(多个线程  都有自己的局部变量)

public class MyThread extends Thread{
       public void run(){
          for(int a=1;a<6;a++){
              System.out.println(currentThread().getName()+":"+a);
              try{
                  sleep(100);  
              }catch(InterruptedException e){
                   System.out.println(e);
              }
          }
       }
       public static void main(String args[]){
               MyThread myThread1 = new MyThread();
               MyThread myThread2 = new MyThread();
               myThread1.start();
               myThread2.start();
               myThread1.run();
      }
}

 

      当主线程执行main()方法时,会创建两个MyThread对象,然后启动两个MyThread线程,接着主线程开始执行第一个MyThread对象的run()方法(此处为调用方法,不要与线程混淆)。主线程、myThread1以及myThread2这三个线程都拥有自己的程序计数器和方法栈,在三个线程各自的方法栈中都有代表run方法的栈帧,在这个帧中存放了局部变量a,即每个线程都拥有自己的局部变量a,它们都分别从1增加到5

     上例中主线程调用MyThread run()方法,而新建线程的run()方法作用是实现该新建线程所要实现的功能,这违背了Thread类提供run()方法的初衷,因此在实际应用中不值得效法。

     举例2.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值