一、基本定义
进程:进程是一个正在执行的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫控制单元换。
线程:进程中的一个独立的控制单元。
二、自定义线程的两种方法
第一种:继承Tread类。步骤如下:
(1)定义继承Tread类的子类;
(2)覆写run()方法;
(3)声明子类对象,并调用start()方法。
注:start()方法有两个作用:启动线程、调用run()方法。
run()方法:存储线程要运行的代码,类似主线程的main()方法中存储主线程的代码。
第二种:实现Runnable接口,步骤如下:
(1)定义实现Runnable接口的类;
(2)覆盖Runnable接口中的run()方法;
(3)创建Runnable子类的对象;
(4)将Runnable子类对象作为参数传递给Tread类的构造方法,建立线程对象;
(5)调用Tread类的start()方法开启线程并调用Runnable接口子类的run()方法。
三、两种方式的区别:
(1)、继承Tread类
编写简单,访问当前进程方便(可以直接使用this);但是无法解决单继承的局限性。
(2)、实现Runnable接口
解决了单继承的局限性,在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想;
但是编写稍微复杂,如果需要当前线程必须使用Thread.currentThread()方法。
四、线程的状态:
创建、运行、冻结、阻塞、消亡。之间的转换如下图。
五、多线程的安全问题
1、问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来。导致共享数据的错误。
2、解决办法:保证操作共享数据的代码只能同时被一个线程使用。
同步代码。
synchronized(对象){
需要同步的代码块,即使用共享数据的代码块。
}
此处的对象如同锁。持有锁的线程可以在同步中执行。没有锁的线程即使获得cpu的执行权,也进不去。
3、同步的前提:
(1)必须有两个以上的线程。(2)必须是多个线程使用同一个锁才使用同步。
4、同步利弊
好处:解决多线程的安全问题。
缺点:多个线程都需要判断锁,消耗资源。
例子:家里门的锁,越多越安全,但是越繁琐,耗资源。
5、如何判断哪些代码该同步:
(1)明确哪些代码是多线程运行代码
(2)明确共享数据
(3)明确多线程运行代码中哪些语句是操作共享数据的代码块。