返回顶部

Java线程

线程对象实现

一、继承Thread类

创建线程的步骤:
  1、定义一个类继承Thread。
  2、重写run方法。
  3、创建子类对象,就是创建线程对象。
  4、调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + ":" + i);
        }
    }
}
MyThread
/*
 * 多线程的实现方式1
 * String getName()      返回该线程的名称。 
 * void   setName(String name) 改变线程名称,使之与参数 name 相同。
 */
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.setName("张三");
        mt.start();
        
        MyThread mt2 = new MyThread();
        mt2.setName("李四");
        mt2.start();
    }
}
ThreadDemo

 

二、实现Runnable接口

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程。

Runnable接口用来指定每个线程要执行的任务。包含了一个 run 的无参数抽象方法,需要由接口实现类重写该方法。

创建线程的步骤:
  1、定义类实现Runnable接口。
  2、覆盖接口中的run方法。
  3、创建Thread类的对象。
  4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
  5、调用Thread类的start方法开启线程。

public class MyThread2 implements Runnable {
    int num;

    public MyThread2(int num) {
        this.num = num;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i + " - " + num);
        }
    }
}
MyThread2
public class ThreadDemo2 {
    public static void main(String[] args) {
        //创建线程实例
        MyThread2 mt = new MyThread2(100);
        Thread t = new Thread(mt);
        t.setName("张三");
        t.start();

        //创建线程实例
        //Thread t2 = new Thread(mt);
        MyThread2 mt2 = new MyThread2(200);
        Thread t2 = new Thread(mt2);
        t2.setName("李四");
        t2.start();
    }
}
ThreadDemo2

 

多线程安全问题采用加锁解决。

 


 

线程状态转换

Java 语言定义了5种线程状态,在某一时刻,一个线程只能有其中的一种状态,这5种状态分别如下:

新建(New):创建后尚未启动的线程处于这种状态。

运行(Runable):Runable 包括了操作系统线程状态中的 Running 和 Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着 CPU 为它分配执行时间。

无限期等待(Waiting):处于这种状态的线程不会被分配 CPU 执行时间,它们要等待被其他线程显式地唤醒。 以下方法会让线程陷入无限期的等待状态:

  • 没有设置 Timeout 参数的 Object.wait() 方法。
  • 没有设置 Timeout 参数的 Thread.join() 方法。
  • LockSupport.park() 方法。

限期等待(Timed Waiting):处于这种状态的线程也不会被分配 CPU 执行时间,不过无须等待被其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。 以下方法会让线程进入限期等待状态:

  • Thread.sleep() 方法。
  • 设置了 Timeout 参数的 Object.wait() 方法。
  • 设置了 Timeout 参数的 Thread.join() 方法。
  • LockSupport.parkNanos() 方法。
  • LockSupport.parkUntil() 方法。

阻塞(Blocked):线程被阻塞了,“阻塞状态”与“等待状态”的区别是:“阻塞状态”在等待着获取到一个排他锁,这个事件将在另外一个线程放弃这个锁的时候发生;而“等待状态”则是在等待一段时间,或者唤醒动作的发生。 在程序等待进入同步区域的时候,线程将进入这种状态。

结束(Terminated):已终止线程的线程状态,线程已经结束执行。上述5种状态在遇到特定事件发生的时候将会互相转换,它们的转换关系如下图。

 注意:

  • wait()方法会释放CPU执行权 和 占有的锁。
  • sleep(long)方法仅释放CPU使用权,锁仍然占用;线程被放入超时等待队列,与yield相比,它会使线程较长时间得不到运行。
  • yield()方法仅释放CPU执行权,锁仍然占用,线程会被放入就绪队列,会在短时间内再次执行。
  • wait和notify必须配套使用,即必须使用同一把锁调用。
  • wait和notify必须放在一个同步块中。
  • 调用wait和notify的对象必须是他们所处同步块的锁对象。

 

Java 线程在JDK 1.2后,线程模型变为基于操作系统原生线程模型来实现。 操作系统支持怎样的线程模型,决定了Java虚拟机的线程是怎样映射。线程模型只对线程的并发规模和操作成本产生影响。

对于 Sun JDK 来说,它的 Windows 版与 Linux 版都是使用一对一的线程模型实现的,一条 Java 线程就映射到一条轻量级进程之中,因为 Windows 和 Linux 系统提供的线程模型就是一对一的。

 

 

posted @ 2017-09-04 02:20  jaden好青年  阅读(134)  评论(0编辑  收藏  举报