前段时间面试被问到启动线程的方法,经常用的就是继承Thread,重写它的run()方法,或者是实现runnable接口,然后被问到还有没有别的方法时,就懵了。今天就是要记录下来。
一、启动线程
1.继承Thread,重写run()方法。
public static void main(String args[]) {
MyThread myThread = new MyThread();
myThread.start();
MyThread myThread2 = new MyThread("A");
myThread2.start();
System.out.println("qqqq");
}
static class MyThread extends Thread{
private String str;
public MyThread() {
// TODO Auto-generated constructor stub
super();
}
public MyThread(String str){
this.str = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
for(int i = 0;i<3;i++){
System.out.println(str+" "+i);
}
}
}
重写run()方法后,调用start()方法。
为什么调用start()方法,而不是run()呢?
多线程就是好多线程在排队等着cpu,调用start()方法,就是让线程进入等待的队列,执行接下来的代码。什么时候轮到使用cpu,什么时候run()方法就会被调用。直接调用run()方法,线程就要等着run()方法执行结束了,才会执行接下来的代码。
上述代码段两个线程都是被start的,执行结果就会出现多种情况。(列出几个例子,并不是全部)
如果上述代码中;两个线程都是被run的,执行结果只有一种。
从多线程的角度考虑,调用start()才是真正的多线程。
2.实现runnable接口
public static void main(String args[]) {
MyRunable myRunable = new MyRunable("B");
Thread thread = new Thread(myRunable);
thread.start();
}
static class MyRunable implements Runnable{
String string;
public MyRunable(String str) {
// TODO Auto-generated constructor stub
string = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<3;i++){
System.out.println(string+" "+i);
}
}
}
运行结果如下:
这两种有什么区别呢?
public static void main(String args[]) {
MyRunable myRunable = new MyRunable();
Thread thread = new Thread(myRunable,"AA");
thread.start();
Thread thread1 = new Thread(myRunable,"BB");
thread1.start();
}
static class MyRunable implements Runnable{
int num = 10;;
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+" "+num--);
}
}
}
}
运行结果
区别就是继承线程,每个线程都是独立的,就不能实现上面代码的效果。实现runnable接口实现线程可以共用runnable,实现上述功能。如果想实现线程独立,不共用runnable就可以了。
还有就是java里面不支持多继承问题,用runnable就可以很好的解决这个问题。
3.FutureTask和Callable
public static void main(String args[]) {
Mycallable mycallable = new Mycallable(1, 2);
FutureTask<Integer> task = new FutureTask<Integer>(mycallable);
Thread thread = new Thread(task);
thread.start();
try {
int sum = task.get();
System.out.println(sum);
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static class Mycallable implements Callable<Integer>{
private int m;
private int n;
Mycallable(Integer a,Integer b){
m = a;
n = b;
}
@Override
public Integer call() throws Exception {
// TODO Auto-generated method stub
int sum = m+n;
return sum;
}
}
与runnable相比,可以获取返回值,也可以捕获一些异常。
4.匿名内部类
这种用的也挺多的,但是一直没有归为一类。这次总结上。
public static void main(String args[]) {
MyThread myThread = new MyThread();
new Thread().start();
new MyThread("AA").start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<3;i++){
System.out.println(i);
}
}
}).start();
}
二、停止一个线程
1.stop
开启一个线程,不管用什么方法,最终都要调用start方法,那么终止一个线程stop就可以了吗?
stop这个方法已经废止了,说是不安全。我理解的是,stop可以使一个正在运行的线程终止,正在运行的线程突然终止,可能是一些资源来不及释放,或者是占用的一些锁来不及解锁。
2.添加退出的条件。
比如在run方法中添加结束的条件。
static class MyThread extends Thread{
private String str;
private int num;
public MyThread() {
// TODO Auto-generated constructor stub
super();
}
public MyThread(String str){
this.str = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
while(num<10){
System.out.println(str+" "+num);
num++;
}
}
}
3.interrupt
public static void main(String args[]) {
MyThread myThread = new MyThread("AA");
myThread.start();
try {
myThread.sleep(20);
myThread.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static class MyThread extends Thread{
private String str;
private int num;
public MyThread() {
// TODO Auto-generated constructor stub
super();
}
public MyThread(String str){
this.str = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
for(int i = 0;i<50000;i++){
System.out.println(str+" "+i);
}
}
}
这样发现线程并没有停下来,interrupt方法,并没有让线程停下来,只是给线程加了一个停止的标志。真正的想要停下来,就有很多方法了,主要还是判断线程的状态,然后停止操作。和方法二有点类似。这里使用判断线程状态+return来实现。
public static void main(String args[]) {
MyThread myThread = new MyThread("AA");
myThread.start();
try {
myThread.sleep(20);
myThread.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static class MyThread extends Thread{
private String str;
private int num;
public MyThread() {
// TODO Auto-generated constructor stub
super();
}
public MyThread(String str){
this.str = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
for(int i = 0;i<50000;i++){
if(isInterrupted()){
return;
}
System.out.println(str+" "+i);
}
}
}