深入探究java多线程之基本方法

JAVA 2016-04-22

  wikipedia:进程线程   多线程是java一项重要的知识点,简单来说进程就是一个应用程序在处理机上的一次执行过程,而进程又可以细分为多个线程,java具备多线程执行的特性,通过其Thread类,可以提高程序运行的效率。   java实现多线程主要有两种方式:   继承Thread类或实现Runnable接口,由于java的单继承特性,所以实现多继承可以通过接口实现的方式。同时要注意多线程运行结果与代码执行顺序无关。   在运行多线程方法时要注意多个线程对相同数据进行操作时是非线程安全的,建议通过添加关键字sychronized对run方法加锁,下面来看一个示例:

public class MyThread extends Thread{
    private  int count=5;
    synchronized  public void run(){
        super.run();
        count--;
        System.out.println("线程 "+this.currentThread().getName()+" 计算 count="+count);
    }
}

  public class Test {
    public static void main(String args[]){
        MyThread mythread=new MyThread();
        Thread a=new Thread(mythread,"A");
        Thread b=new Thread(mythread,"B");
        Thread c=new Thread(mythread,"C");
        Thread d=new Thread(mythread,"D");
        a.start();
        b.start();
        c.start();
        d.start();
    }
}

  运行结果是:

线程 B 计算 count=4 线程 C 计算 count=3 线程 D 计算 count=2 线程 A 计算 count=1

  如果去掉sychronized关键字,结果是:  

线程 A 计算 count=3 线程 D 计算 count=1 线程 C 计算 count=2 线程 B 计算 count=3

count值出现不一致性,如果是用于银行系统,那么将造成严重后果。

  sychronized的具体作用在于将具体对象或方法加锁,加锁的代码称为“互斥区”或者“临界区”,当线程想要执行里面的方法时,必须先判断锁是否解除,若没有,则一直等待,直至锁解除。   下面介绍几个常用的方法:   1.如果要判断线程是否处于活动状态,可以使用isAlive()方法(活动状态即线程启动但尚未终止)   2.sleep()方法也经常被使用,作用是使正在执行的线程休眠,单位是毫秒。   3.getId()可以获取线程在计算机中的唯一标识   4.如果要停止线程,目前有三种方法 1.执行完毕,正常退出 2.stop()方法(不建议使用) 3.interrupt()方法   下面来具体看看interrupt()方法

   public class MyThread extends Thread{
    private  int count=5;
      public void run(){
        super.run();
        for(int i=1;i<10001;i++){
            System.out.println("i= "+i);
        }
    }
}
public class Test {
    public static void main(String args[]){
        try {
            MyThread mythread = new MyThread();
            mythread.start();
            Thread.sleep(1000);
            mythread.interrupted();
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}

  可以看到,输出是i=1到i=10000,并没有发生终止的情况。   可见interrupt方法并不会直接停止线程,而是设置了一种中断状态,那么该如何判断中断状态呢?我们在API文档中科院看到两种似乎一样的方法,interrupted()和isInterrupted()方法

  但是它们是不同的,interrupted()测试当前线程是否处于中断状态,并在执行后将中断状态标识置为false,isInterrupted()同样能做出判断,但是不清除状态。   看一段测试程序:

  public class Test {
      public static void main(String args[]){

       Thread.currentThread().interrupt();
                System.out.println("是否停止1?="+Thread.currentThread().interrupted());
                System.out.println("是否停止2?="+Thread.currentThread().interrupted());
                System.out.println("end!");
            }
        }

  输出为:

是否停止1?=true 是否停止2?=false end!

  如果把两个interrupted()换成isInterrupted(),那么输出为:   

是否停止1?=true 是否停止2?=true end!

  充分印证了上文的观点。

  5.暂停和恢复线程可以使用suspend()和resume()方法,要注意的是这两种方法是独占式且不能同步的,如果不能及时释放锁,程序将一直停止。   6.yield()方法的作用是放弃当前CPU资源,让给其它任务占用,但要注意放弃的时间不确定。   7.setPriority(),线程优先级的确定,优先级高的线程理论上将得到更多资源,java中线程优先级分为1-10,默认为5。要注意的是优先级具备继承性。且优先级高的通常先执行完,但并不是绝对的:

   public class MyThread1 extends Thread{
      public void run(){
          long beginTime = System.currentTimeMillis();
          for (int i = 0; i < 1000; i++) {
              Random random = new Random();
              random.nextInt();
          }
          long endTime = System.currentTimeMillis();
          System.out.println("--------thread 1 use time=" + (endTime - beginTime));
    }
}
public class MyThread2 extends Thread{
    public void run(){
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            Random random = new Random();
            random.nextInt();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("********thread 2 use time=" + (endTime - beginTime));
    }
}
public class Test {
    public static void main(String args[]){
        for (int i = 0; i < 5; i++) {
            MyThread1 thread1 = new MyThread1();
            thread1.setPriority(5);
            thread1.start();
            MyThread2 thread2 = new MyThread2();
            thread2.setPriority(6);
            thread2.start();
        }
    }
} 

  将thread1和thread2优先级设为5和6,运行多次后发现,结束时间并不总是thread2先于thread1.

  最后来说说守护线程,它是相对与用户线程而言的,即只要进程中有线程存在,必然伴随着守护线程,例如垃圾回收器,它可以是系统的,也可以是用户定义的,所以作用不固定。

  以上就是java多线程的基础知识,其它知识将在之后的文章继续讨论。


本文由 Tony 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

赏个馒头吧