创建线程的三种方式(继承Thread,实现Runnable,实现callable)
继承Thread(不推荐使用,具有单继承局限性)
public class StartThread extends Thread{
//线程入口点
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i+"杨玉环真好玩!");
}
}
public static void main(String[] args) {
//创建线程对象
StartThread startThread = new StartThread();
startThread.start(); //调用start方法启动一条新线程
//mani线程,主线程
for (int i = 0; i < 10000; i++) {
System.out.println("鲁班好可爱");
}
//startThread.run();//这里使用run方法不会开辟新线程,执行完run方法后会又回到主线程
/*
鲁班好可爱
5杨玉环真好玩!
6杨玉环真好玩!
7杨玉环真好玩!
8杨玉环真好玩!
9杨玉环真好玩!
鲁班好可爱
可以知道,主线程和创建的线程是交替执行的
*/
}
}
实现Runnable(推荐使用,它可以对同一资源开启多个线程)
package com.Luoking.Thread;
public class Runnable01 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
if(ticket<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket+"张票");
ticket--;
}
}
public static void main(String[] args) {
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01,"小敏").start();
new Thread(runnable01,"小杰").start();
new Thread(runnable01,"小平").start();
}
}
但是实现Runable会出现并发问题,多个线程操作同一个资源,会出现线程不安全,数据紊乱
小敏拿到了第100张票
小敏拿到了第99张票
小敏拿到了第98张票
小杰拿到了第100张票
//这里第100张票出现了两次,在现实生活中,不可能存在
实现callable
package com.Luoking.Thread;
import java.util.concurrent.*;
public class testCallable implements Callable<Boolean> {
//重写call方法,线程执行体就在call中
@Override
public Boolean call() throws Exception {//重写的call方法需要抛出异常
for (int i = 0; i < 10; i++) {
System.out.println("执行到"+i+"步");
}
return true; //与其他开启线程不同的地方,这个开启线程会有返回值
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
testCallable T1 = new testCallable();
testCallable T2 = new testCallable();
testCallable T3 = new testCallable();
//开启线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
//线程池执行
Future<Boolean> s1 = pool.submit(T1);
Future<Boolean> s2 = pool.submit(T2);
Future<Boolean> s3 = pool.submit(T3);
//获取结果, 需要抛出异常
Boolean b1 = s1.get();
Boolean b2 = s1.get();
Boolean b3 = s1.get();
//关闭线程池
pool.shutdownNow();
}
}