【First step to the last one】JAVA多线程整理(三)--线程属性、线程的等待唤醒、线程锁释放

来源:互联网 发布:mac 移动硬盘win 编辑:程序博客网 时间:2024/06/06 02:18

㈠线程属性

线程作为一个对象,包含了自己特有的属性。线程常见的属性如下

◇ ID属性: 用于标识线程,可以使用Thread类中的getId()方法获得该属性值,但是该属性不能修改。

◇ Name属性: 用于标识线程,主要是为了方便程序员区分线程。可以使用Thread类中的getNameI()方法获得该属性值。也可以使用setName()方法修改该属性值。

◇ priority属性: 用于表示线程的优先级,高优先级的线程可能有较高的几率获得自由。该属性与底层操作系统密切相关。java中的线程优先级范围是1~10。可以使用Thread类中的getPriority()方法和setPriority()方法获得和设置该属性值。

◇ Daemon属性: 用于表示线程是否是守护线程。守护线程的作用为其他线程提供服务。如果系统中仅剩下守护线程,则虚拟机会退出。可以使用Thread类中setDaemon()方法设置线程是否为守护线程,方法的参数是一个布尔值。

获得线程各属性的代码实例如下:

public class test4 {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubnew Thread(new Monday("DOG0")).start();  //启动线程new Thread(new Monday("DOG1")).start();  new Thread(new Monday("DOG2")).start();  new Thread(new Monday("DOG3")).start();  try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}  Thread current = Thread.currentThread();      System.out.println(current.getPriority());   //线程优先级System.out.println(current.getName());   //该线程名字System.out.println(current.activeCount());   //当前线程的线程组中活动线程的数目System.out.println(current.getId());         //该线程的标识符System.out.println(current.getThreadGroup());//该线程所属的线程组System.out.println(current.getStackTrace()); //返回一个表示该线程堆栈转储的堆栈跟踪元素数组System.out.println(current.hashCode());      //该线程的哈希码值System.out.println(current.toString());      //返回该线程的字符串表示形式,包括线程名称、优先级和线程组}}class Monday implements Runnable  {      private String name;         public Monday(String name)      {          this.name = name;      }      public void run()      {      //在run()方法里获取线程信息的方法:Thread.currentThread().getId(),其他信息获取如此        System.out.println(this.name+" 当前线程ID号:"+Thread.currentThread().getId());        try          {              Thread.sleep(1000);          }          catch (InterruptedException e)          {              e.printStackTrace();          }      }    public String getName() {return name;}public void setName(String name) {this.name = name;}  } 

□插播一个知识点:什么情况可以导致线程停止?

主要考察的是线程状态的转换。所谓当前线程停止执行,包含了当前xiancheng转为等待状态和当前线程转换为终止状态两种情况,导致线程停止可能有以下几个方面的原因:

◇线程在执行时,如果程序中某段代码抛出InterruptException异常。那么当前线程就转为终止线程,使线程停止。

◇如果当前线程执行了sleep()方法,那么当前线程转为等待状态,也会使得线程停止。

◇如果另外一个高优先级的线程处于可运行状态,有可能会让当前线程转为等待状态,这与操作系统有关系。

◇如果当前线程执行了InputStream类的read()方法,可以让当前线程转为等待状态,也会使得当前线程停止。

对线程的停止分析,对程序的调试有非常重要的作用。如果程序出现了线程停止的问题,可以针对以上列出的问题来调试程序。


㈡线程的等待唤醒(wait()、notify())

wait、notify和notifyAll方法是Object类的final native方法。所以这些方法不能被子类重写,Object类是所有类的超类,因此在程序中有以下三种形式调用wait等方法。

wait();//方式1:this.wait();//方式2:super.wait();//方式3

●void notifyAll()

解除那些在该对象上调用wait方法的线程的阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是对象锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

●void notify()

随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态。该方法只能在一个同步方法或同步块内部调用。如果当前线程不是对象锁定的持有者,该方法会抛出一个IllegalMonitorStateException异常。

●void wait()

导致线程进入等待状态直到它被通知。该方法只能在一个同步方法中调用。如果当前线程不是对象锁的持有者,该方法会抛出一个IllegalMonitorStateException异常。

●void wait(long millis)

●void wait(long millis, int nanos)

导致线程进入等待状态直到它被通知或者经过指定的时间。这些方法只能在一个同步方法中调用。如果当前线程不是对象锁的持有者,该方法会抛出一个IllegalMonitorStateException异常。

参数: millis        毫秒数

          nanos      纳秒数

□synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。  

(引用自:http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html)
1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:  public synchronized void accessVal(int newVal);  
synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。  在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。  

synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。  

2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:  
synchronized(syncObject) {  
//允许访问控制的代码  
}  
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。  

对synchronized(this)的一些理解 
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。  

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。  

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。  

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。  

五、以上规则对其它对象锁同样适用


实例程序:

public class test5 {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubPrintThread pd = new PrintThread();         //定义本类对象Thread td1 = new Thread(pd);                //定义线程对象Thread td2 = new Thread(pd);td1.setName("DOOM");                        //设置线程名称td2.setName("PUCK");td1.start();                                //驱动线程td2.start();}}class PrintThread implements Runnable {/*自定义锁对象,这样代价最小,也可使用当前对象this*/private byte[] lock = new byte[0];              public void run() {synchronized (lock) {for (int i = 0; i < 100; i++) {if(i%10==0 && 0!= i){try {lock.notify();              //唤醒另一个等待对象锁的线程lock.wait();//本线程等待其他线程notify} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+i);}}lock.notify(); //由于本线程同步块代码运行完毕,但仍需notify,以便其他线程使用对象锁System.out.println(Thread.currentThread().getName()+": END");}}}

㈢线程锁释放

Java多线程运行环境中,在哪些情况下会使对象锁释放?

由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的。在以下情况下,持有锁的线程会释放锁:
(1)执行完同步代码块,就会释放锁。(synchronized)
(2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。(exception)
(3)在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放锁,进入对象的等待池。(wait)
除了以上情况以外,只要持有锁的线程还没有执行完同步代码块,就不会释放锁。
在下面情况下,线程是不会释放锁的:
(1)执行同步代码块的过程中,执行了Thread.sleep()方法,当前线程放弃CPU,开始睡眠,在睡眠中不会释放锁。
(2)在执行同步代码块的过程中,执行了Thread.yield()方法,当前线程放弃CPU,但不会释放锁。
(3)在执行同步代码块的过程中,其他线程执行了当前线程对象的suspend()方法,当前线程被暂停,但不会释放锁。




















0 0
原创粉丝点击