java多线程
在明白什么是java多线程之前,我们需要也了解什么是进程和线程?
进程:进程是“程序执行的一个实例” ,进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。(简单点说,进程就是正在执行的程序,例如电脑上正在运行的qq,微信等。)
线程:线程是进程的一个执行流,独立执行它自己的程序代码,是操作系统能够进行运算调度的最小单位。
在java中创建多线程的主要方式有三种:
1.继承Thread类(重写run()方法)
2.实现Runnable接口(重写run()方法)
3.实现Callable接口(存在返回值)
这里我们需要注意下,我们通常是通过实现Runnable接口来创建线程,比继承Thread类的好处:
1.Thread类是Runnable接口的实现类。
2.采用实现接口的方式,解决了java单继承的问题。
3.Runnable接口实现的多线程更加清楚的描述数据共享的概念。
以上便是多线程的简单创建方式
下面我们来看一个例子:
创建三个线程对输出1-100
我们的理想结果本应该是:100,99,98......1这样按照顺序打印,然而结果却是:
线程同步之间的问题的简单解析(画的图没办法上传??):线程0 在拿到cpu的执行权后,当还没执行x--时,线程2 获得cpu的执行权,而此时的x任然为100,在线程2还没执行到x--时,也有可能失去cpu的执行资格,此时线程3拿到cpu的执行权,此时的x任为100,所以会出现上面的问题。
下面我们先来了解两个原理方便对线程同步的认知:
1.java多线程内存原理(共享数据内存):
java内存模型规定了所有的变量都存储在主内存中,每条线程都还有自己的工作内存,线程的工作内存中保存了被线程使用到的变量的内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读取主内存中的变量。不同的线程之间也不能直接访问对方内存的变量,线程间变量的传递需要通过主内存来完成。
2java多线程内存原理(方法内部的私有变量):
线程方法内部的私有变量,不存在线程安全问题,java虚拟机运行时时数据区,虚拟机栈或者本地方法是线程安全的,每个线程都有自己的虚拟机栈存储区和本地方法栈,所以线程在执行方法时,方法内部的变量不会牵扯到共享这一原则。
对于java共享数据的同步安全问题,通常使用synchronized关键字或者Lock接口锁,来确保数据的安全,加了锁之后,当线程拿到cpu的执行权后,只有当线程内的代码执行完,才释放执行权,其他线程才有可能获取到cpu的执行权。当线程释放执行权后,同时会把修改后的共享数据返回到主内存中,当其他先线程再次获取到执行权,会从主内存中拷贝共享数据到自己的线程中。
下面我们来修改之前的代码,并观察结果
这里需要注意的时,线程间的同步锁一定要时同一个。