标签:
1. 进程与线程
进程:正在运行中的程序。每个进程拥有自己的一整套变量。
线程:进程中一条执行路径。线程共享数据。每个线程在栈区中都有自己的执行空间,自己的方法区、自己的变量。
2. 多线程
一个进程中至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序。
线程运行必须要通过类中指定的方法开启:start方法。
start方法:1)启动了线程 2)让jvm调用了run方法
创建线程的方式:
|--继承Thread类
步骤:
1. 定义类继承Thread类;
2. 复写run方法,将要让线程运行的代码都存储到run方法中;
3. 通过创建Thread类的子类对象,创建线程对象;
4. 调用线程的start方法,开启线程,并执行run方法。
|--实现Runnable接口
1. 定义类实现Runnable接口;
2. 覆盖接口中的run方法(用于封装线程要运行的代码);
2. 通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数;
为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。
3. Thread类对象调用start方法开启线程。
为什么要有Runnable接口的出现?
1. 通过继承Thread类的方式,可以完成多线程的建立。但是如果一个类已经有了自己的父类,就不可以继承Thread类,因为Java单继承的局限性。
而实现Runnable接口可以避免单继承的局限性。
2. 其实是将不同类中需要被多线程执行的代码进行抽取。将多线程要运行的代码的位置单独定义到接口中,为其他类进行功能扩展提供了前提。
所以Thread类在描述线程时,内部定义的run方法,也来自于Runnable接口。
线程运行状态:
被创建: start()
运行: 具备执行资格,同时具备执行权。
冻结: sleep(time), wait()-notify()唤醒;线程释放了执行权,同时释放执行资格。
阻塞:具备执行资格,没有执行权。
消亡:stop()
3. 多线程安全
多线程安全问题的原因:
因为cpu的快速切换,哪个线程获得了cpu的执行权,哪个线程就执行。
1)多个线程在操作共享数据
2)有多条语句对共享数据进行运算
解决安全问题的原理:
只要将操作共享数据的语句在某一时段让一个线程执行,在执行过程中,其他线程不能进来执行。
4. 线程同步
好处:解决了线程安全问题。
弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁问题。
定义同步前提:
1)必须要有两个或两个以上的线程,才需要同步。
2)多个线程必须保证使用的是同一个锁。
同步函数:将同步关键字定义在函数上,让函数具备了共同性。
1)同步函数使用的锁是this锁。
2)当同步函数被static修饰时,锁对象是该类的字节码文件对象:类名.class
同步函数和同步代码块的区别?
1. 锁对象:同步代码块使用的锁可以是任意对象;同步函数分两种情况。
2. 在一个类中只有一个同步,可以使用同步函数;如果有多同步,必须使用同步代码块。
同步死锁:
通常只要将同步进行嵌套,就可以看到现象。同步函数中有同步代码块,同步代码块中有同步函数。
等待唤醒机制:(因为这些方法都需要定义在同步中,所以三个方法都定义在Object类中)
wait:将同步中的线程处于冻结状态,释放执行权,释放执行资格。同时将线程对象存储到线程池中。
notify:唤醒线程池中某一个等待线程。
notifyAll:唤醒的是线程池中的所有线程。
wait和sleep区别:
wait(可以指定时间也可以不指定时间;不指定时间只能由对应的notify或者notify唤醒):线程会释放执行权,而且会释放锁。
sleep(必须指定时间,时间到自动从冻结状态转成运行状态):线程会释放执行权,但不释放锁。
Lock接口:将锁对象封装成对象来处理
同步是隐式的锁操作,而Lock对象是显示的锁操作,它的出现代替了同步。
Lock接口中没有直接操作等待唤醒的方法,而是将这些方式单独封装到了一个对象中:Condition。
Condition接口:await(), signal(), signalAll()
Java基础-多线程
标签:
原文地址:http://www.cnblogs.com/troy-sxj/p/4351499.html