Java 多线程(二)线程创建
三种创建方式
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口(了解)
继承Thread类
自定义线程继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
可以看到,他们是交替执行的,具体执行顺序看cpu调度,每次调度情况也不会相同
线程开启不一定立即执行,由cpu调度执行
//创建线程方式一 public class TestThread1 extends Thread{ @Override public void run() { //run()方法线程体 for (int i = 0; i < 20; i++) { System.out.println("我在看代码--"+i); } } //main主线程 public static void main(String[] args) { //创建线程对象 TestThread1 testThread1 = new TestThread1(); //调用start()方法开启线程 testThread1.start(); for (int i = 0; i < 200; i++) { System.out.println("我在学习多线程"+i); } } }
实现Runnable接口
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
//创建线程方式二 public class TestThread2 implements Runnable{ @Override public void run() { //run()方法线程体 for (int i = 0; i < 20; i++) { System.out.println("我在看代码--"+i); } } //main主线程 public static void main(String[] args) { //创建Runnable接口对象实现类对象 TestThread2 testThread2 = new TestThread2(); //创建线程对象,通过线程对象开启线程 // Thread thread = new Thread(testThread2); // thread.start(); new Thread(testThread2).start(); for (int i = 0; i < 200; i++) { System.out.println("我在学习多线程"+i); } } }
下面举一个具体的例子,多个线程同时操作一个对象,并初识并发问题,以买火车票为例
public class TestThread3 implements Runnable{ //火车票票数 private int ticketNum = 10; @Override public void run() { while(true) { if (ticketNum <= 0) { break; } //模拟延时 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNum-- + "票"); } } public static void main(String[] args) { TestThread3 testThread3 = new TestThread3(); new Thread(testThread3,"小明").start(); new Thread(testThread3,"小红").start(); new Thread(testThread3,"小强").start(); new Thread(testThread3,"小黄").start(); } }
可以看到,多个人都拿到了同一张票。我们发现多个线程操作一个资源的情况下,线程不安全,数据紊乱
我们再写一个具体的例子,龟兔赛跑。
public class Race implements Runnable{ //胜利者 private static String winner; @Override public void run() { for (int i = 0; i <=100 ; i++) { //模拟兔子睡觉 if (Thread.currentThread().getName().equals("兔子") && i%10==0){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } //判断比赛是否结束 boolean flag = gameOver(i); if (flag){ break; } System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步"); } } //判断比赛是否结束 private Boolean gameOver(int steps) { if (winner != null) { return true; } { if (steps >= 100) { winner = Thread.currentThread().getName(); System.out.println(winner +"赢了"); return true; } } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
实现Callable接口
1.实现Callable接口,需要返回值类型
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1)
5.提交执行:Future<Boolean> result1 = ser.submit(t1)
6.获取结果:boolean r1 = result1.get()
7.关闭服务:ser.shutdownNow()
小结
继承Thread类:
子类继承Thread类具备多线程能力
启动线程:子类对象.start()
不建议使用:避免oop单继承局限性
实现Runnable接口:
实现接口Runnable具备多线程能力
启动线程:传入目标对象+Thread对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用