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();
}
}
}
}