1、使用上的区别,看代码
class MyThread extends Thread
{
@Override
public void run() {
System.out.println("do things");
}
}
class MyRunnable implements Runnable
{
@Override
public void run() {
System.out.println("do things");
}
}
结论:
可以看到使用Thread是继承关系,而使用Runnable是实现关系。我们知道java不支持多继承,如果要实现多继承就得要用implements,所以使用上Runnable更加的灵活
2、 共享数据问题
Runnable是可以共享数据的,多个Thread可以同时加载一个Runnable,具有并发特点。当各自Thread获得CPU时间片的时候开始运行runnable,runnable里面的资源是被共享的
首先分别定义一个thread和一个runnable,things这个变量即为所想要共享的资源
class MyThread extends Thread
{
int things = 5;
@Override
public void run() {
while(things > 0)
{
System.out.println(currentThread().getName() + " things:" + things);
things--;
}
}
}
class MyRunnable implements Runnable
{
String name;
public MyRunnable(String name)
{
this.name = name;
}
int things = 5;
@Override
public void run() {
while(things > 0)
{
things--; System.out.println(name + " things:" + things);
}
}
}
随后,用三个Thread来运行看:
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
MyThread thread3 = new MyThread();
thread1.start();
thread2.start();
thread3.start();
}
}
输出结果如下:
Thread-0 things:5
Thread-0 things:4
Thread-2 things:5
Thread-1 things:5
Thread-1 things:4
Thread-1 things:3
Thread-1 things:2
Thread-1 things:1
Thread-2 things:4
Thread-2 things:3
Thread-2 things:2
Thread-2 things:1
Thread-0 things:3
Thread-0 things:2
Thread-0 things:1
结论:可以看到每个Thread都是5个things,所以资源是不共享的
下面用一个Runnable在3个Thread中加载尝试看看:
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args) {
MyRunnable run = new MyRunnable("run");
Thread th1 = new Thread(run, "Thread 1");
Thread th2 = new Thread(run, "Thread 2");
Thread th3 = new Thread(run, "Thread 3");
th1.start();
th2.start();
th3.start();
}
}
输出结果如下:
run things:3
run things:2
run things:1
run things:0
run things:3
一共打印出了5次,表示things资源使用了5次
3、线程Thread的5状态
创建:执行new方法创建对象,即进入创建状态
就绪:创建对象后,执行start方法,即被加入线程队列中等待获取CPU资源,这个时候即为就绪状态
运行:CPU腾出时间片,该thread获取了CPU资源开始运行run方法中的代码,即进入了运行状态
阻塞:如果在run方法中执行了sleep方法,或者调用了thread的wait/join方法,即意味着放弃CPU资源而进入阻塞状态,但是还没有运行完毕,带重新获取CPU资源后,重新进入就绪状态
停止:一般停止线程有两种方式:1执行完毕run方法,2调用stop方法,后者不推荐使用。可以在run方法中循环检查某个public变量,当想要停止该线程时候,通过thread.para为false即可以将run提前运行完毕,即进入了停止状态
4、线程分类
1】用户线程:比如主线程,连接网络的线程
2】守护线程:运行在后台,为用户线程服务 Thread.setDeamon,必须在start方法前调用。守护线程里面不能做IO读写的操作。因为当用户线程都结束后,守护线程也会随jvm一起被销毁,如果这个时候守护线程里面还有IO未完成的操作,就会崩溃
总结:
1、java不支持多继承,如果要实现多继承就要用implements,所以实现Runnable比继承Thread更灵活
2、多个线程操作同一个线程资源,Runnable方式支持数据共享,Thread不支持