Java线程:状态转换,同步与锁

来源:互联网 发布:java计算时间间隔 编辑:程序博客网 时间:2024/05/21 10:05
 

一、     线程的状态转换

线程的状态转换是线程控制的基础。

线程状态总的可分为五大状态:

生(新)、可运行、运行、等待/阻塞、死。

生(新)线程对象已经创建,还没有在其上调用start()方法。

可运行:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。

运行:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。

 等待/阻塞:这是线程有资格运行时它所处的状态。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。

:当线程的run()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一死亡,就不能复生。如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

二、阻止线程执行

对于线程的阻止,考虑一下三个方面,不考虑IO阻塞的情况:

睡眠;等待;因为需要一个对象的锁定而被阻塞。

睡眠:

Thread.sleep(long millis);

Thread.sleep(long millis, int nanos);

睡眠用于减慢线程,在睡眠时间不可运行。

睡眠原因:线程执行太快,或者需要强制进入下一轮,因为Java规范不保证合理的轮换。

try {
            Thread.sleep(123);
        } catch (InterruptedException e) {
            e.printStackTrace(); 
        }

睡眠位置一般在run()函数内。

2、线程的优先级和线程让步yield()

yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程。 

设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。例如:

        Thread t = new MyThread();
        t.setPriority(8);
        t.start();

 线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:

static int MAX_PRIORITY
          线程可以具有的最高优先级。
static int MIN_PRIORITY
          线程可以具有的最低优先级。
static int NORM_PRIORITY
          分配给线程的默认优先级。

3、Thread.yield()方法

    Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。

yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

4、join()方法 

让一个进程b加入到另一个进程a的尾部。在a执行完毕之前,b不能工作

。例如:

        Thread t = new MyThread();
        t.start();
        t.join();

join()方法还有带超时限制的重载版本。 例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。

join为非静态方法,定义如下:

void join()    
    等待该线程终止。    
void join(long millis)    
    等待该线程终止的时间最长为 millis 毫秒。    
void join(long millis, int nanos)    
    等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。

Java线程:线程的同步与锁

一、  同步问题提出

线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。

有时可能出现由于线程同时访问一个对象而造成结果的不合理性,这时的方法就是限制访问次数,每次只允许一个线程访问。

在具体的Java代码中需要完成一下两个操作:

把竞争访问的资源类Foo变量x标识为private;

同步哪些修改变量的代码,使用synchronized关键字同步方法或代码

二、同步和锁定

锁的原理

Java中每个对象都有一个内置锁

当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。

当程序运行到synchronized同步方法或代码块时才该对象锁才起作用。

一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放。

释放锁是指持锁线程退出了synchronized同步方法或代码块。

静态方法同步

   要同步静态方法,需要一个用于整个类对象的锁,这个对象是就是这个类(XXX.class)。

例如:

public static synchronized int setName(String name){

      Xxx.name = name;

}

等价于
public static int setName(String name){
      synchronized(Xxx.class){
            Xxx.name = name;
      }

线程同步小结

1、线程同步的目的是为了保护多个线程访问一个资源时对资源的破坏。

2、线程同步方法是通过锁来实现,每个对象都有切仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。

3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获得锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。

4、对于同步,要时刻清醒在哪个对象上同步,这是关键。

5、编写线程安全的类,需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断,对“原子”操作做出分析,并保证原子操作期间别的线程无法访问竞争资源。

6、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。

7、死锁是线程间相互等待锁锁造成的,在实际中发生的概率非常的小。真让你写个死锁程序,不一定好使,呵呵。但是,一旦程序发生死锁,程序将死掉。