Java多线程

Java实现多线程有两种方法,一是继承Thread类,二是实现Runnable接口。

继承Thread类

继承Thread类,并重写Thread类中的run()方法。调用父类 Thread中start()方法启动线程。

继承Thread类实例:

public class Q {
    public static void main(String[] args) {
        //创建一个A类的实例对象
        A a = new A();
        //启动线程
        a.start();
        //main函数
        System.out.println("main method");
    }
}

class A extends Thread{
    public void run(){
        System.out.println("Hello World!");
    }
}

运行结果:
main method
Hello World!
表明两个线程运行完毕。

上面的例子使用了自定义的类继承Thread类来实现多线程,还有更简单的方式,先前不需要定义一个类继承Thread类,直接使用Thread类本身,并重写Thread类中的run()方法来实现多线程。实例如下:

public class Q {
    public static void main(String[] args) {
        //创建一个Thread类的实例,在创建时重写run()方法。
        Thread t = new Thread(){
            public void run(){
                System.out.println("Thread类的线程");
            }
        };
        t.start();
        System.out.println("main方法的线程");
    }
}

运行结果如下:
main方法的线程
Thread类的线程

实现Runnable接口

实现Runnable接口主要是为了解决单继承所带来的不便。

首先我们来看一下Thread类其中的一个构造方法:

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

显然,此构造方法接受Runnable类型的参数。所以,所有实现Runnable的类都可以作为参数传递给Thread类的构造方法中。实例如下:

public class Q {
    public static void main(String[] args) {
        //创建一个A类的实例
        A a = new A();
        //创建一个Thread类对象
        Thread t = new Thread(a);
        //开启线程
        t.start();
        System.out.println("main method");
    }
}

class A implements Runnable{
    public void run(){
        System.out.println("实现Runnable接口实现多线程");
    }
}

运行结果如下:
main method
实现Runnable接口实现多线程

当然,我们要活学活用,或许我们可以不用传入实现Runnable的类的实例,而是传入继承了Thread类的实例作为参数。Thread类本身已经实现了Runnable接口,所以Thread类的构造方法可以接收Thread类本身以及Thread类的子类、实现Runnable接口的类。我们可以通过一个继承了Thread类的类的实例来作为参数传递给Thread类的构造方法中。实例如下:

public class Q {
    public static void main(String[] args) {
        //创建一个A类的实例对象
        A a = new A();
        //创建一个Thread类的实例
        Thread t = new Thread(a);
        //启动线程
        a.start();
        //main函数
        System.out.println("main method");
    }
}

class A extends Thread{
    public void run(){
        System.out.println("Hello World!");
    }
}

运行结果:
main method
Hello World!

大家可以和通过A类的实例a直接启动线程的方式做一下比较,两种方式的效果完全相同。

还可以通过匿名内部类的方式实现多线程,注意,匿名内部类的类不是class的意思,是type的意思,意味着类和接口都可以作为匿名内部类。实例如下:

public class Q {
    public static void main(String[] args) {
        //创建一个Thread类对象,构造方法传入匿名的Runnable接口,必须重写Runnable接口的方法。
        Thread t = new Thread(new Runnable(){
            public void run(){
                System.out.println("Anonymous inner type");
            }
        });
        System.out.println("main method");
    }
}

synchronized关键字

synchorized修饰方法,称为同步方法;修饰代码块,称为同步代码块。

首先我们来看一个没有使用synchronized关键字的多线程程序:

public class Q {
    public static void main(String[] args) {
        //创建一个A对象
        A a = new A();
        //创建两个线程t1、t2,共享a对象,线程名字取不同
        Thread t1 = new Thread(a, "线程1");
        Thread t2 = new Thread(a, "线程2");
        t1.start();
        t2.start();
    }
}

class A implements Runnable{

    int num = 10;

    public void run(){
        while (num > 0) {
            System.out.println(Thread.currentThread().getName()+",num = "+num);
            num--;
        }
    }
}

运行结果:
线程1,num = 10
线程2,num = 10
线程1,num = 9
线程2,num = 8
线程1,num = 7
线程2,num = 6
线程1,num = 5
线程2,num = 4
线程1,num = 3
线程2,num = 2
线程1,num = 1

线程t1、t2本身是共享一个对象的成员变量num的,但打印出两个线程都为10的状况,这就是没有使用synchronized关键字所出现的问题。

使用过后的状况(以synchronized同步代码块为例):

public class Q {
    public static void main(String[] args) {
        //创建一个A对象
        A a = new A();
        //创建两个线程t1、t2,共享a对象,线程名字取不同
        Thread t1 = new Thread(a, "线程1");
        Thread t2 = new Thread(a, "线程2");
        t1.start();
        t2.start();
    }
}

class A implements Runnable{

    int num = 100;

    public void run(){
        while (true) {
            synchronized (this) {
                if (num > 0) {
                    System.out.println(Thread.currentThread().getName()+",num = "+num);
                    num--;
                } else {
                    break;
                }
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
posted @ 2017-01-25 23:06  晚樨  阅读(124)  评论(0编辑  收藏  举报