单线程和多线程
进程
(1)线程依赖于进程
(2)进程是正在运行的程序。是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
(3)多进程意义:单进程的计算机只能做一件事情,多进程的计算机可以做多件事情,可以同时运行多个程序,提高CPU的使用率
注意:两个程序不会同时运行,单CPU在一个时间点上只能做一件事,我们认为是同时运行是因为CPU在做着程序间的高效切换
线程
(1)在同一个进程内可以执行多个任务,而每一个任务可以看做是一个线程
(2)线程是程序的执行单元,执行路径,是程序使用CPU最基本的单位
(3)单线程:程序有一条执行路径
(4)多线程:程序有多条执行路径
(5)多线程意义:提高程序的使用率。程序的执行其实都是在抢CPU的资源,CPU的执行权。多个进程是在抢这个资源,而其中如果某一个进程执行路径较多,就会有更多几率抢到CPU的执行权
(6)不能保证那个线程在哪个时刻抢到资源,所以线程的执行有随机性
并行和并发
并行:逻辑上同时发生,指在某一个时间段内同时运行多个程序
并发:物理上同时发生,指在某一个时间点同时运行多个程序
Java程序的运行原理
由java命令启动JVM,JVM启动就相当于启动了一个进程。接着由该进程创建了一个主线程去调用main方法
JVM是多线程的,原因是垃圾回收线程也要先启动,否则内存会溢出。
垃圾回收线程加上主线程,最低启用两个线程。
如何实现多线程
线程依赖进程存在,而进程是由系统提供的,所以应调用系统功能创建一个进程。Java不能直接调用系统功能,所以不能直接实现多线程程序。但Java可以调用C/C++写好的程序来实现多线程程序。
由C/C++调用系统功能创建进程,然后由Java调用,Java提供一些类供我们使用(Thread),就可以实现多线程.
多线程实现
方式一:继承Thread类
步骤:
(1)自定义类继承Thread
(2)自定义类重写run()
不是类中的所有代码都需要被线程执行的。为了区分哪些代码需要被线程执行,java提供了Thread类中的run()来包那些被线程执行的代码
(3)创建对象
(4)启动线程
run()和start()的区别:run()仅仅是封装被线程执行的代码,直接调用是普通方法;start()首先启动了线程,然后使jvm调用该线程的run方法
注意:多次调用stsrt()方法相当于线程被多次调用,而不是启动多个线程,多个线程启动需要创建多个线程对象(创建多个自定义类对象),再分别用start()启动线程
方式二:实现Runnable接口
(1)自定义类实现Runnable接口
(2)自定义类重写run()
(3)创建Runnable对象
(4)把(3)创建的对象作为参数传给Thread
注意:接口Runnable没有getName(),因此可使用Thread.currentThread().getName()获取线程对象名称
实现Runnable接口的好处:
1.避免Java单继承的局限性
2.适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现面向对象的思想
获取和设置线程对象名称
获取线程对象名称:Thread的getName(),也可用带参构造方法取名,但是该方法属于Thread,需要在自定义类写一个带参构造方法
不是Thread类的子类中如何获取线程对象名称:public static Thread currentThread()返回对当前正在执行的线程对象的引用。————>Thread.currentThread().getName()
例如获取main的线程名称
设置线程对象名称:Thread的setName()
多线程安全问题
是否有安全问题的标准
(1)是否是多线程环境
(2)是否有共享数据
(3)是否有多条语句操作共享数据
解决办法:
(1)和(2)的问题改变不了,所以从(3)着手
1)思想:把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
利用Java提供的:同步机制