java 线程创建的方法

来源:互联网 发布:皮皮麻将 乐玩网络 编辑:程序博客网 时间:2024/05/23 00:00

这几天开始学习java并发编程实战,发现这本书理论知识很多,实践并不多,而且基本知识貌似默认大家是知道的。所以边看边学习一下基础知识。

1.首先看下官方API文档的介绍:

  • JVM允许在一个程序中同时有多个运行的线程。
  • 每个线程都有一个优先级(priority),优先级高的线程运行时要优先于优先级低的线程,每个线程要么是守护线程,要么不是。当一个线程在运行时创建另一个线程是,新线程最初的优先级和创建它的线程一样。一个线程是守护线程当且仅当创建它的线程是守护线程。
    -创建线程有两种方法,一种是继承Thread类并实现Run()方法,另一种是实现Runnable接口并实现run方法。

2.第一种方法:继承Thread类并实现run方法

public class MyThread extends Thread {    //可以指定线程的名字    public MyThread(String threadName){ super(threadName); }    public void run() {        for(int i = 0; i < 5; i++) {        System.out.println(Thread.currentThread().getName() + " " + i);        //请求让出对CPU的占用,即主动请求切换线程,但是实际切换不切换要看CPU心情        Thread.yield();    }    }    public static void main(String[] agrs) {    new MyThread("thread 1").start();    new MyThread("thread 2").start();    new Thread().start();   }}result:thread 2 0thread 1 0thread 2 1thread 1 1thread 2 2thread 1 2thread 2 3thread 1 3thread 2 4thread 1 4

这里main方法中最后的线程就是Thread类本身而不是它的子类,虽然文档上讲需要实现Run方法,但Run方法Thread实现Runnable方法后必须实现的,并不是abstract方法,不实现也不会报错,但是不实现的话这个线程其实啥都不会做,因为Run方法是空的。
因为main中两个线程的优先级是相同的,所以执行顺序并不确定,每次运行的结果都是随机的。
Thread类的构造器有:
Thread()
Thread(Runnable target) //指定Runnable,与后面第二种方法有关
Thread(String name) //指定线程的名称
Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target) //指定线程组
Thread(ThreadGroup group, String name)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)

3.第二种方法:实现Runable接口,并实现run方法

class MyThread implements Runnable {    public void run() {        for(int i = 0; i < 5; i++) {        System.out.println(Thread.currentThread().getName() + " " + i);        Thread.yield();        }    }    public static void main(String[] args) {        new Thread(new MyThread(),"thread 1").start();        new Thread(new MyThread(),"thread 2").start();    }}result:thread 2 0thread 1 0thread 1 1thread 1 2thread 1 3thread 1 4thread 2 1thread 2 2thread 2 3thread 2 4

在这里因为是实现接口,所以就必须实现Run()方法了。

4.特别方法:匿名内部类

public class MyThread {    public static int num = 1;    public static void getNum() {         for(int i = 0; i < 5; i++){            System.out.println(Thread.currentThread().getName() + " " + num++);            Thread.yield();        }    }    public static void main(String[] args){        Thread thread1 = new Thread(new Runnable() { public void run() { MyThread.getNum();} },"thread1");        Thread thread2 = new Thread(new Runnable() { public void run() { MyThread.getNum();} },"thread2");        thread1.start();        thread2.start();        try {            thread1.join();        } catch (InterruptedException e1) {            // TODO Auto-generated catch block            e1.printStackTrace();        }        try {            thread2.join();        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println(MyThread.num);    }}result:thread1 1thread2 1thread1 2thread2 3thread1 4thread2 5thread1 6thread2 7thread1 8thread2 910

这里其实还是第二种方法,只不过是用匿名内部类实现。但是仔细观察输出的结果,thread 1和thread 2 都输出一个num = 1(这是程序重复运行好几次才偶尔出现的)。这个因为我的MyThread类并不是线程安全的,当都多个线程同时访问这个类的数据并且数据有更改时,可能得到错误的数据。这是下一篇线程安全的问题啦。

4.总结

其实构造线程无非就是继承和实现接口两种方法,但是具体的形式可以有很多种,比如第三种方法,但是万变不离其宗。另外,多线程编程一定和线程安全和锁是紧密联系。
Thread类的方法由于现在还不需要用到,所以以后在总结。官方API文档对方法介绍的都很好,比如虽然有destroy方法,但是这个方法在现实编程中不能使用,因为他会产生线程死锁等危害。

0 0