黑马程序员——线程

来源:互联网 发布:mysql招聘 编辑:程序博客网 时间:2024/06/05 17:45
线程的两种实现方法:继承Tread类和实现Runable接口。
线程
线程(thread)是控制线程(thread of control)的缩写。
线程有:自己的方法代码,方法中定义的局部变量(栈中),共享数据。
线程是独立的,局部变量不能被其他线程访问,若两个线程同时访问同一个方法,每个现在讲各自得到属于自己的一份该方法的拷贝。
继承Thread类创建线程
1.自定义类ThreadType继承Thread类,在类中覆写Thread类的run()方法(Thread类中run为空方法,什么都不做)。
2.创建线程类对象 ThreadType tt=new ThreadType();
3.启动新线程 tt.start()。 新线程会自动调用run()方法。start方法不等run()执行完毕就返回了。
实现Runable接口创建线程
1.自定义类ThreadType实现Runable接口,在类中覆写Runable接口的run()方法(run方法由Runable提供)
2.创建Runable变量指向ThreadType对象 Runable rb=new ThreadType();
3.创建线程类对象 Thread td=new Thread(rb);//通过Thread类的来创建线程类对象
4.启动新线程 td.start()


线程周期
一个线程有4种状态:
new 新建。new后,start之前。可以用start进入启动状态,也可stop进入退出状态。
runnable 可运行。start之后。可运行状态不一定就在运行,取决于优先级和系统调度。
non runnable 不可运行。线程被挂起或发生阻塞。使用resume,notify或notifyAll可使其到可运行状态。
done 退出。调用stop()或者run()结束会自动到done状态。 done状态无法返回到其他状态。
            当程序所有线程均处于done状态,程序会被强制终止。
线程状态转换函数
start()          new--runnable

stop()           new/runnable--done     容易在虚拟机引起“死锁”,不建议使用。建议等自然终止
suspend()挂起    runnale--non runnable  容易在虚拟机引起“死锁”,不建议使用。建议sleep()或wait()
resume()恢复     non runnale--runnable  容易在虚拟机引起“死锁”,不建议使用。建议sleep()或wait()

sleep()暂停      runnable--non runnable--runnable sleep(long)毫秒,sleep(long,int)纳秒
wait()阻塞       runnable--non runnable
notify()解除阻塞 non runnable--runnable 一般使用notifyAll(),除非明确知道唤醒哪个线程
yield()明确放弃执行 runnale--runnable
线程状态转换
线程进入runnable
1.其他线程调用notify()或者notifyAll(),唤醒non runnable状态的线程
notify()唤醒一个线程并允许它获得锁,notifyAll()唤醒所以等待这个对象的线程并允许它们获得锁。
2.线程调用sleep(),到时间后自动进入runnable状态。
3.线程对I/O操作的完成。
线程进入runnable
1.线程调用wait()。只有其他线程调用notify()或者notifyAll(),才会获得锁和被唤醒,然后改线程一直等待重新获得对象锁才继续执行。wait() throws InterruptedException
2.线程调用sleep()的等待时间段。sleep() throws InterruptedException
3.线程等待I/O操作的完成。
等待线程结束
有时候需要等待一个线程结束再执行其他代码。
isAlive()判断一个线程是否存活(runnable和non runnable都返回true,new和done返回false)。
join()等待该线程结束。可带参数规定等待的上限时间。0或空表示无限等待。(long,int)表毫秒,纳秒。
       join() throws InterruptedException

线程调度
java中,CPU的使用通常是抢占式调度模式,不需要时间片分配进程。
抢占式调度模式是指 多线程处于可运行状态,但只有一个线程正在运行。当该线程运行结束或者进入非可运行状态,或者其它具有更高优先级的线程进入可运行状态,该线程会让出CPU。
getPriority() 获取线程优先级。返回int,表示线程优先级。
setPriority() 设置线程优先级。参数为int。
优先级的范围 Thread.MIN_PRIORITY 到 Thread.MAX_PRIORITY (1到10)。
windows系统支持三种,Thread.MIN_PRIORITY,Thread.NORM_PRIORITY,Thread.MAX_PRIORITY(值为5)

线程同步
java中多线程可以共享资源,多线程以并发模式访问共享数据时,可能会发生冲突。
线程同步机制可以实现共享数据的一致性,保证多线程有序访问共享数据,而不是同时操作共享资源。
java提供“锁”机制实现线程同步。
“锁”机制实现方法是在共享代码前加 sychronized 关键字(这种代码称为 同步代码)。
“锁”机制的原理是 每个线程进入共享代码之前获得锁,没有锁无法进入共享代码。线程在退出共享代码时或则sleep()及wait()等待期间会释放锁。 这就解决了多线程竞争共享代码的情况,达到线程同步。
java中,有一个 同步模型监视器,专门管理具有同步代码的对象。它的原理是为每个具有同步代码的对象准备一把 唯一的锁,只有获取锁的对象才可以进入同步代码,其他的线程可以通过wait()阻塞停留在对象中等待。
其他线程可以用notify()或者notifyll()唤醒该阻塞线程。
同步方法:在一个类中,用sychronized 关键字定义的方法为 同步方法。
同步格式
public sychronized 返回值类型 方法名(){}  //同步方法
sychronized(对象obj){}   //同步块。线程必须获得对象obj的锁,才可以访问该代码块。必须万分注                           意 obj对象的作用范围。
public void method(){
Object obj=new Object();
synchronized(obj)
{//代码}
}
上面的代码创建的是局部对象。由于每个线程执行到Object obj=new Object();都会创建一个新对象,都可以获得新对象的锁,所以这段代码起不到同步作用。
如果同步的是类的成员,情况就会不同了。
class method(){
Object obj=new Object();
public void test(){
synchronized(obj)
{//代码}
}
}
有时可以通过以下方式同步代码块
public void method(){
synchronized(this){}//通过this获得调用该方法的对象,也可以保证对象的唯一性,实现同步
}
如果一个类中有多个synchronized(this)同步块,有一个线程访问其中一个synchronized(this)同步块,其他的线程不能访问任何一个synchronized(this)同步块。
synchronized(ClassName.class){}同步块,调用ClassName对象实例的线程,只有一个线程能访问该对象。
Lock接口
 lock()方法用于锁定对象,unlock()方法用于释放对对象的锁定,他们都是在Lock接口中定义的方法。位于这两个方法之间的代码在被执行时,效果等同于被放在synchronized同步块中。一般用法是将需要在lock()和unlock()方法之间执行的代码放在try{}块中,并且在finally{}块中调用unlock()方法,这样就可以保证即使在执行代码抛出异常的情况下,对象的锁也总是会被释放,否则的话就会为死锁的产生增加可能。 
    和synchronized关键字不同,lock只把当前方法锁定,其他的方法(不论是同步还是非同步的)并没有被锁定。
java1.5中    
 Lock 替代了synchronized 
 Condition 替代了 Object监视器方法

好处:将同步synchronized 替换成了 Lock
      将object中的wait notify notifyAll 替换成了 Condition对象
      该对象可以Lock锁进行获取。一个锁可以对应多个Condition对象
注意:释放锁的工作一定要执行
示例代码

private Lock lock=new ReentrantLock();
private Condition condition =lock.newCondition();

public void cet(String name ) throws 
{
   lock.lock();
   try
   {
      while(flag)
           contidition.await();
       this.name=name+"--"+count++;

       sop(Thread.currentThread().getName()+"...生产者..."+this.name)
       flag=true;
        condition.signalAll();

    }

0 0