------ android培训、java培训、期待与您交流! ----------
一、多线程的概述和用法
1. 多线程的概念
进程:正在执行的程序,它是应用程序运行的一块区域。
线程:进程的执行路径,执行单元。是最小的执行单位。
一个程序在运行的时候,里面的各个功能操作可以同时运行,这些操作也就是执行单元,可以理解为线程,这些线程可以同时运行有多条执行路径这种现象,叫多线程.
2. 多线程的作用
多线程让程序各个功能可以同时进行,效率大大提升.
3. 多线程的用法
两个关键字:Thread(类) Runnable(接口) Thread实现了Runnable
两种方式:
一 继承Thread
步骤:
(1)自定义一个类继承Thread类。
(2)继承后重写Thread类中的run方法,把需要实现的代码放入里面去。
(3)通过Thread类或者自定义类创建线程对象。
(4)通过对象调用start方法来启动线程。
例:
class A extends Thread
{
A(Srting name)这个方法可以给线程命名,如果要命名就写
{
super(name)
}
public void run
{
//要实现的代码
System.out.println(Thread.currentThread().getName()+this.name+"线程启动.");
}
}
class Test
{
public static void main(Strting[] args)
{
A a =new A("线程1");\
a.start();
//要启动多少个线程,就创建多少个对象.并start.
}
}
二 实现Runnable接口
这种方式与继承最大的区别在于,实现的Runnable里没有start方法,
但Thread类里有个方法可以接收Runnable类型对象.
并用用start()方法启动这个对象.里的run方法
步骤:
(1)自定义一个类实现Runnable接口。
(2)实现Runnable接口中的run方法。
(3)通过Thread类创建线程对象,并把自定义类作物参数传递。
(4)通过对象调用start方法。
class B implments Runnable
{
public run{具体代码实现}
}
class Test
{
public static void main(Strting[] args)
{
B a =new B();
Thread t = new Thread(a);
t.start();
//要启动多少个线程,就创建多少个对象.并start.
}
}
4.多线程在什么时候用?
当一个程序里的多个功能关系并不是很紧密,也就是说没有先执行哪个才能执行哪个时,我们可以让里面的各个功能模块独立线程,这样要使用的时候就可以多线程,并同时运行.
5. 多线程的特点?
1,平时多用实现方法创建对程,因为比较接口可以任意实现,没有限制,如果是继承,那么执行一个线程,便要创建一个这个类的对象,那么就又初始化了一次,这样不利于操作同一数据库.除非用静态数据让其与所有对象共享.
2.多线程里各线程执行是随机的,都是在抢夺cpu执行权.
3.线程运行时以run开始,以run方法运行完结束.中途如果被其它线程抢夺cpu执行权,那么会进入临时阻塞状态.直到抢回来后,运行完后再销毁.
二、多线程同步
1. 什么是同步?
同步,(关键字是synchrownized,)就是其修饰的一个代码块,或方法,里只能,够有一个线程在运行
2. 同步的用处?
当我们用多线程操作同一数据时,由于线程执行的的不确定性,有可能会出现多个线程重复操作同一数据,比如每次生产一个产品就要出库一个产品,如果线程在生产时暂停了,那么进来一个新线程,同时其又启动了,这时就会产生两个产品,而没有出库.这就产生了安全隐患,如果.
用了同步,那么外面的线程只能等里面的线程执行完后,才能进来,去执行,这就避免了这个情况的产生.
3. 同步的用法
snychronized一般与方法wait() 等待 notify() 唤醒最先等待的那个线程
notifyAll()唤醒所有 ,这三个方法都在Object类中,而Object是所有类的超类.
wait()方法会抛出一个异常,所以要用到try({}catch(){};
格式:
修饰方法:在返回值前加snychronized
修饰代码:snychronized(对象){同步代码}
这个对象可以随便一个,有两个要注意,本类名.class,this 但是如果要和方法上的为同一个,只能用this.
1.5以后的替换用法以:Lock
在snychronized体系中,等待唤醒其是一种普及操作,
notify 与 wait(),没有具体联系,是独立的,只与线程偶合性高,唤醒是看哪个线程先等待, 由线程属性决定
而Lock,体系中,把wait() notify() notifyAll()封装为一个Condition对象,(一个Lock可以对应多个Condition对象,)
那么同时等待与唤醒就有了对应关系,就是说我的等待只能我唤醒,其就具有了从属关系,
每当唤醒与我同一个对象里的等待,与线程等待先后没有关系,那么便可以通过等待与唤醒放置位置的不同,
灵活的控制不同线程的等待与唤醒
使用方法:
1.要先导包,因为其不在lang包中,import java.util.concurrent.locks.*;
2.创建一个把锁:Lock 锁名 = new Lock();
3.创建condition对象 Condition c1 =锁名.newCondition();
Condition c2=锁名.newCondition();.....还可以有很多....
换成三个方法:await() signal() signalAll()
这里要注意,这个方法直接返回一个与当前创建的锁Lock关联的Condition对象,
不然加锁就没意义,只能锁这个锁返回的condition对象,这是Lock与synchronized(隐式锁机制)最大的区别.synchronized对所有等待唤醒起作用且如何操作我们不知道
4.使用就是
在要锁的代码最开始加:锁名.lock();
要实现的加锁的代码,[放入等待:里面具体放哪个看自已需要:如比:放try{c1.await()}catch(Exception e){}
.......
.......
唤醒:c2.signal(); 这个也是自已控制
最后:
finally
{锁名.unlock();}....释放锁一定要执行.
这样我们唤醒只会唤醒自已的等待.
4. 什么时候用?
当需要控制流程,让线程按我们的需求操作共享数据时,这个时候就用同步,也就是线程间需要通信
5. 同步的特点?
注意:notify 与notifyAll能唤醒的都是同一把锁对象所关联的wait,也就是一把锁synchronized是对应同其一组的wait notifyAll等
如果同步synchronized存在于非静态方法上,那么在代码块上表示同一锁就是this,,代表本类对象
如果,存在于静态方法中,那么在代码上表示同一把锁的对象就是本类名.class
类名.class是返回本类的class对象
多线程里的锁,也叫监视器.
被锁同步的方法里或代码内,只能允许一个线程运行.其它的要么冻结,要么阻塞
线程中两个类似功能的wait()与sleep(时间),
区别:
1.sleep一定要传时间告诉它要睡眠多久,在这个时间段内它会释放cpu执行权,直到这个时间过去它会自动唤醒然后等待cpu执行权再继续执行,而wait可以没有这个时间.
2.sleep可以放于任何位置,而wait只能放于同步中.
3.sleep只是释放cpu执行权,而没有释放锁,但是wait锁也放了,cpu执行权也放了.