进程
进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程
就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程至少有一个线程。
jvm启动时,会有一个进程java.exe。该进程中至少有一个线程负责java程序的执行。
而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
其实更细节的说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。
创建线程的两种方式
继承Thread
- //继承Thread创建线程
- class MyThread extends Thread
- {
- public void run()
- {}
- }
- //开启线程
- new MyThread().start();
实现Runnable接口
- //实现Runnable接口
- class ImplRunnable extends Runnable
- {
- public void run()
- {
- }
- }
- //开启线程
- new Thread(new ImplRunnable).start();
多线程的安全问题
当多个线程在访问同一个共享数据时,会产生安全隐患,一个线程对数据访问还没有结束,另一个线程就开始访问共享数据,导致共享数据错误。
解决办法
对多个线程访问同一个共享数据,只能让一个线程访问完毕后,其他线程在访问,在线程访问时其他线程不允许访问。
java对于多线程的安全问题提供了专业的解决方式,同步代码块。
同步代码块
- synchronized(对象)
- {
- //需要被同步的代码;
- }
对象如同同步锁,持有锁的线程可以在同步中执行。
典型例子:毕向东老师说的,火车上的卫生间。
同步的前提
1.必须要有两个或者两个以上线程。
2.必须是多个线程使用同一个锁(类的class文件对象在内存中唯一的,唯一锁)
必须保证同步中能有一个线程在运行
同步的好处和弊端
同步的好处:解决了多线程的安全问题
同步的弊端:多个线程需要判断锁,较为消耗资源。
如何查找安全问题
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据的
同步的两种形式
1.同步代码块(对象锁)
2.同步函数(this对象锁)
静态函数的函数锁是class,因为静态函数不可以定义this,它使用的是该方法所在类的字节码对象,静态进内存时,内存中没有本类对象,但是一定有该类对于的字节码文件对象类名.class它的类型是Class。
死锁
同步嵌套同步,而锁却不同,例如同步A需要A锁,同步B需要B锁,一个线程持有A锁,另一个线程持有B锁,A同步块要进入B同步块,同时B同步要进入A同步块,可能都没有释放所,就会出现死锁,程序停止那里不动了。
- /*
- 实现Runnable的Test类
- */
- class Test implements Runnable
- {
- private boolean flag;
- Test(boolean flag)
- {
- this.flag = flag;
- }
- public void run()
- {
- if(flag)//如果true执行if的同步代码块
- {
- synchronized(MyLock.locka)
- {
- System.out.println("if...locka");
- synchronized(MyLock.lockb)
- {
- System.out.println("if...lockb");
- }
- }
- }
- else//如果false执行else中的同步代码块
- {
- synchronized(MyLock.locka)
- {
- System.out.println("else...locka");
- synchronized(MyLock.lockb)
- {
- System.out.println("else...lockb");
- }
- }
- }
- }
- }
- /*
- 要用到对象锁locka和lockb
- */
- class MyLock
- {
- static Object locka = new Object();
- static Object lockb = new Object();
- }
- /*
- 死锁测试
- */
- class DeadLockTest
- {
- public static void main(String[] args)
- {
- //开启两个线程让他们争夺cpu执行权,查看可能出现的死锁情况
- Thread t1 = new Thread(new Test(true));
- Thread t2 = new Thread(new Test(false));
- t1.start();
- t2.start();
- }
- }