Java并发编程(一)——线程

来源:互联网 发布:英雄岛全套源码下载 编辑:程序博客网 时间:2024/04/29 16:24

Java并发编程(一)——线程

一,线程的实现方式

  Java中实现多线程有两种方式,如下:

1,继承java.lang.Thread类,重载它的run()方法; 2,实现java.lang.Runnable接口,重载接口中的run()方法。

  这两种实现方式没有优劣,但由于Java中不允许多继承,所以使用第二种实现接口的方式更加灵活。
  另外需要注意的是实现了Runnable的类,就像其字面描述的意思一样,只是一个可运行的东西,最终也是要Thread类来启动它,它才能跑起来。这一点从源码上分析来看,只能说Runnable接口只是为了用来在不能多继承的情况下来实现多线程而设计的,最终线程的内容和启动还是Thread来实现的。
  代码如下:

    public class ThreadDemo {        public static void main(String[] args) {            Thread t = new Thread();            t.start();            Thread t2 = new Thread(new Line());            t2.start();        }    }    class Line implements Runnable{        @Override        public void run() {            System.out.println("Line Thread is running...");        }    }

  而更多的情况下,我们会采用匿名内部类来实现多线程:

    public static void main(String[] args) {        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("I'm a new Thread");            }        }).start();    }

 其实,从另外一个角度来看,参照Thread类的run方法(如下),如果没有Runnable的实例target,单独启动一个Thread是没有意义的。但这样就可以说必须组合使用Thread和Runnable才是正确的吗?不是的,因为run()方法是可以被覆盖的,Thread的子类覆盖run方法,启动也可以的。

    /* What will be run. */    private Runnable target;    @Override    public void run() {        if (target != null) {            target.run();        }    }

二,线程的生命周期

  线程的生命周期是指一个线程从创建到消亡的过程。

  • 新建状态(New)
      当用new操作符创建一个新的线程对象时,该线程处于创建状态。处于创建状态的线程只是一个空的线程对象,系统不为它分配资源。
    注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadStateException异常。如下:
    Thread t = new Thread(new Runnable() {        @Override        public void run() {            try {                Thread.sleep(3000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("I'm a new Thread");        }    });    t.start();    t.start();//同一个(同id)线程不能同时启动两次

另,线程是不能clone的,因为线程id是不能重复的,会抛出CloneNotSupportedException异常,见源码:

    @Override    protected Object clone() throws CloneNotSupportedException {        throw new CloneNotSupportedException();    }
  • 就绪状态(Runnable)
      线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
  • 运行状态(Running)
      就绪状态的线程获取了CPU的使用权,执行程序代码的过程就处于运行态。
  • 阻塞状态(Blocked)
      阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (1)等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
    (2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    (3)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态(Dead)
      线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

三,线程状态的转换

1,线程生命周期图

这里写图片描述
这里写图片描述

2,线程状态的切换方式:

1)yield():yield的意思是让步,让出,就是暂时让出CPU的使用权,所以从Running变为了Runnable状态。
2)sleep():使线程睡眠一定的时间,由Running态变为Blocked态。
3)join():使当前线程(如主线程)挂起,直到调用join方法的线程执行完毕。
4)exit():在线程进入Running之前可以清空并退出该线程。
5)stop():强制线程退出,已废弃
6)suspend():挂起线程,由Running变为Blocked,和resume相对应,已废弃
7)resume():恢复线程,由Blocked变为Runnable,已废弃
8)interrupt():打断/中断线程。

四,Thread类的常用API

void setName(String name):为线程设置线程名;
  守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。
void setDaemon(boolean on):设置是否是守护线程,是谁的守护线程?是当前线程的守护线程;需要在start方法调用之前使用;另,在Daemon线程中产生或新建的新线程默认也是Daemon的。

public class DaemonDemo {    public static void main(String[] args) throws InterruptedException {        TestThread test = new TestThread();        // 如果不设置daemon,那么线程将输出10后才结束        test.setDaemon(true);        test.start();        System.out.println("isDaemon = " + test.isDaemon());        try {            System.in.read(); // 接受输入,使程序在此停顿,一旦接收到用户输入,main线程结束,守护线程自动结束        } catch (IOException ex) {            ex.printStackTrace();        }    }}class TestThread extends Thread {    public void run() {        for (int i = 1;; i++) {            try {                Thread.sleep(1000);            } catch (InterruptedException ex) {                ex.printStackTrace();            }            System.out.println(i);        }    }}

boolean isDaemon():判断是否是守护线程;
void setPriority(int newPriority):设置线程优先级,默认为5,最小为1,最大为10;优先级越高,越能更早的获取CPU调度;
Thread currentThread():返回当前线程对象的一个引用,为什么不用this?见下篇博客
int activeCount():返回当前线程所在的线程组中活跃线程的数量;

0 0
原创粉丝点击