Java多线程(全)

it2024-07-14  42

多线程

1.程序、进程、线程

在操作系统中运行的程序就是进程;

一个进程可以有多个线程;

程序是指令和数据的有序集合,是一个静态的概念;

而进程则是执行程序的一次执行过程,是一个动态的概念;

进程是系统资源分配的单位

线程是CPU调度和执行的单位

真正的多线程是指多个cpu,即多核

理解:进程相当于一个类,类中有多个方法(即多个线程),main()方法即(主线程),gc线程。

main()方法即(主线程)为系统的入口,用于执行整个程序;线程的运行是由调度器安排调度,不能人为干预;对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制线程会带来额外的开销,如cpu的调度时间,并发控制开销每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

2.线程的创建

三种创建方式

Thread class

继承Thread类

Runnable接口

实现Runnable接口

Callable接口

实现Callable接口

3.Thread

自定义类继承Thread重写run()方法;创建对象,调用start()开启线程 import javax.xml.transform.Source; public class TestThread01 extends Thread{ //继承Thread类 //总结:线程开启不一定立即执行,有CPU调度执行 @Override public void run() { //run()方法线程体 for (int i = 0; i < 20; i++) { System.out.println("**********-4564646465"); } } //main线程,即主线程 public static void main(String[] args) { TestThread01 testThread01 = new TestThread01(); //testThread01.start();//线程开启,交替(类似同时)执行,电脑单核只有一个cpu testThread01.run();//这个在前,先执行run(); for (int i = 0; i < 20; i++) { System.out.println("7554574545*********"); } } }

多线程实现多张图片同时下载

import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; public class TestThread02 extends Thread{ private String url; private String name; public TestThread02(String url,String name){ this.url=url; this.name=name; } public TestThread02(){ } @Override public void run() { //下载线程 WebDownloader webDownloader = new WebDownloader(); try { webDownloader.downloader(url,name); System.out.println(name); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { TestThread02 testThread02 = new TestThread02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603037822768&di=5f0cc79b7c104781de8cea48c7d8b1ca&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2Fmonth_1012%2F10120514509c7244b23f4a2fa5.jpg","a.jpg"); TestThread02 testThread03 = new TestThread02("https://ns-strategy.cdn.bcebos.com/ns-strategy/upload/fc_big_pic/part-00720-1746.jpg","a1.jpg"); TestThread02 testThread04 = new TestThread02("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2441956749,4275399915&fm=26&gp=0.jpg","a2.jpg"); testThread02.start(); testThread03.start(); testThread04.start(); } } //下载器 class WebDownloader{ //下载方法 public void downloader(String url,String name) throws IOException { FileUtils.copyURLToFile(new URL(url),new File(name)); } }

4.Runnable

推荐使用Runnable对象,因为Java单继承的局限性

定义MyRunnable类实现Runnable接口实现run()方法,编写线程执行体创建线程对象,调用start()方法启动线程 public class TestRunnable01 implements Runnable{ public void run() { for (int i = 0; i < 20; i++) { System.out.println("*******************"); } } public static void main(String[] args) { TestRunnable01 testRunnable01 = new TestRunnable01(); new Thread(testRunnable01).start(); } }

5.小结

继承Thread

子类继承Thread类具备多线程能力启动线程:子类对象.start()不建议使用:避免OOP单继承局限性

实现Runnable接口

实现接口Runnable具备多线程能力启动线程:传入目标对象+Thread对象。start()推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

多个线程操作同一个资源问题

//多个线程操作同一个资源 //模拟买票 //发现问题:多个线程操作同一个人资源的情况下,线程不安全,数据紊乱。 public class TestRunnable02 implements Runnable{ private int ticket=10; public void run() { while (true){ if (ticket<=0){ break; } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticket--+"票"); } } public static void main(String[] args) { TestRunnable02 runnable02=new TestRunnable02(); new Thread(runnable02,"小鹏").start(); new Thread(runnable02,"小强").start(); new Thread(runnable02,"小慧").start(); } }

6.实例:龟兔赛跑

import org.omg.Messaging.SyncScopeHelper; public class Race implements Runnable{ private static String winner; public void run() { for (int i = 0; i <= 100; i++) { //模拟兔子睡觉 if (Thread.currentThread().getName().equals("兔子")&&i%50==0){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } //判断100步 if (win(i)){ break; } System.out.println(Thread.currentThread().getName()+"跑了"+i+"步"); } } //判断胜利者 public boolean win(int step){ if (winner!=null){ return true; } if (step>=100){ winner=Thread.currentThread().getName(); System.out.println("胜利者是"+winner); } return false; } public static void main(String[] args) { Race race=new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }

7.Callable

8.静态代理模式

//静态代理模式总结: //真实对象和代理对象都要实现同一个接口 //代理对象要代理真实对象 //好处: //代理对象可以做很多真实对象做不了的事情 //真实对象专注做自己的事情 public class StaticProxy { public static void main(String[] args) { WeCompany weCompany=new WeCompany(new You()); weCompany.HappyMarry(); } } interface Marry{ void HappyMarry(); } class You implements Marry{ public void HappyMarry() { System.out.println("结婚"); } } class WeCompany implements Marry{ private Marry marry; public WeCompany(Marry marry) { this.marry = marry; } public void HappyMarry() { before(); this.marry.HappyMarry(); after(); } public void before(){ System.out.println("结婚之前,布置现场"); } public void after(){ System.out.println("结婚之后,收尾款"); } }

9.Lamda表达式

函数式接口:只有一个抽象方法的接口

对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

lambda推导过程代码

import java.awt.peer.LabelPeer; /* 推到lambda表达式 */ public class TestLambda { //3.静态内部类 static class Like2 implements ILikeLamb{ public void lambda() { System.out.println("i like lambda2***"); } } public static void main(String[] args) { //方式1使用外部类 ILikeLamb like = new Like1(); like.lambda(); //方式2使用静态内部类 like=new Like2(); like.lambda(); //4.局部内部类 class Like3 implements ILikeLamb{ public void lambda() { System.out.println("i like lambda3!!!"); } } //方式3使用局部内部类 like=new Like3(); like.lambda(); //5.匿名内部类 like=new ILikeLamb() { public void lambda() { System.out.println("i like lambda4~~~~~~"); } }; //方式4使用匿名内部类 like.lambda(); //6.lambda表达式 like=() -> { System.out.println("i like lambda5~***~~"); }; //方式5使用lambda表达式 like.lambda(); } } //1.定义一个函数式接口 interface ILikeLamb{ void lambda(); } //2.实现类 class Like1 implements ILikeLamb{ public void lambda() { System.out.println("i like lambda"); } }

lambda简化

class TestLambda2 { public static void main(String[] args) { //局部内部类 class Love implements ILove{ @Override public void live(int a) { System.out.println("i love number is"+a); } } ILove love=new Love(); love.live(666); //匿名内部类 love=new ILove() { @Override public void live(int a) { System.out.println("i love number is"+a); } }; love.live(888); //lambda表达式 love=(int a)-> { System.out.println("i love number is"+a); }; love.live(999); //简化1,去参数类型 love=(a)-> { System.out.println("i love number is"+a); }; //简化2.去括号 love=a-> { System.out.println("i love number is"+a); }; //简化3.去花括号 love = a -> System.out.println("i love number is"+a); //总结: //方法中只有一行代码才可以简化花括号,多行得用{}; //前提接口必须是函数式接口; //多个参数得同时都去掉类型,却得用()括起来(a,b,c); } } interface ILove{ public void live(int a); }

10.线程状态

五种状态

两张图对比理解

11.线程方法

12.线程停止

自定义停止代码

public class ThreadStop implements Runnable{ private boolean flg=true; @Override public void run() { int i=0; while (flg){ System.out.println("running**********"+i++); } } public static void main(String[] args) { ThreadStop threadStop=new ThreadStop(); new Thread(threadStop).start(); for (int i = 0; i < 500; i++) { System.out.println("main线程"+i); if (i==444){ threadStop.stop(); System.out.println("该线程停止了***************"); } } } public void stop(){ this.flg=false; } }

13.线程休眠

模拟倒计时

//模拟倒计时 public class ThreadSleep2 implements Runnable{ private int ticket=10; @Override public void run() { while (true){ if (ticket <= 0) { break; } //模拟延时 try { Thread.sleep(1000); System.out.println(ticket--); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { ThreadSleep2 threadSleep2=new ThreadSleep2(); new Thread(threadSleep2).start(); } }

模拟时钟

import java.text.SimpleDateFormat; import java.util.Date; //模拟时钟 import static java.lang.System.currentTimeMillis; public class ThreadSleep3 { public static void main(String[] args) { //获取当前系统时间 Date time= new Date(System.currentTimeMillis()); while (true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(time)); time= new Date(System.currentTimeMillis());//更新时间 } catch (InterruptedException e) { e.printStackTrace(); } } } }

14.线程礼让

礼让线程,让当前正在执行的线程暂停,但步阻塞将线程从运行状态转为就绪状态让CPU重新调度,礼让不一定成功!看CPU心情 //礼让不一定成功 public class ThreadYield { public static void main(String[] args) { MyYield myYield=new MyYield(); new Thread(myYield,"aaa").start(); new Thread(myYield,"bbb").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"开始执行"); Thread.yield(); System.out.println(Thread.currentThread().getName()+"停止执行"); } }

15.Join

Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞可以想象成插队 //测试join//类似于插队 public class ThreadJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName()+"来了"+i); } } public static void main(String[] args) { ThreadJoin threadJoin = new ThreadJoin(); Thread thread=new Thread(threadJoin,"vip"); thread.start(); for (int i = 0; i < 100; i++) { if (i==40){ try { thread.join();//强势插入,主线程阻塞 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("main来了"+i); } } }

16.线程状态观测

Thread.State

线程可以处于以下状态之一:

NEW 尚未启动的线程处于此状态。RUNNABLE 在Java虚拟机中执行的线程处于此状态。BLOCKED 被阻塞等待监视器锁定的线程处于此状态。WAITING 正在等待另一个线程执行特定动作的线程处于此状态。TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。TERMINATED 已退出的线程处于此状态。

17.线程的优先级

set和get–priority()

低优先级只意味着调度概率低,并不是优先级低就不会被先调用。

测试代码

public class ThreadPriority { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); MyThread myThread=new MyThread(); Thread thread1=new Thread(myThread); Thread thread2=new Thread(myThread); Thread thread3=new Thread(myThread); Thread thread4=new Thread(myThread); Thread thread5=new Thread(myThread); //设置优先级 thread1.setPriority(6); thread1.start(); thread2.setPriority(2); thread2.start(); thread3.setPriority(8); thread3.start(); thread4.setPriority(4); thread4.start(); thread5.setPriority(10); thread5.start(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); } }

18.守护(daemon)线程

线程分为用户线程和守护线程

虚拟机必须确保用户线程执行完毕

虚拟机不用等待守护线程执行完毕

如,后台记录操作日志,监控内存,垃圾回收等

public class ThreadDaemon { public static void main(String[] args) { Gad gad=new Gad(); Our our=new Our(); Thread t=new Thread(gad); Thread t1=new Thread(our); t.setDaemon(true);//用户线程默认false t.start(); t1.start(); } } class Gad implements Runnable{ @Override public void run() { while (true){ System.out.println("Gad NB alone living"); } } } class Our implements Runnable{ @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("living*********living"+i); } System.out.println("death---------death=-"); } }

19.线程同步

多个线程操作同一个资源

并发:同一个对象被多个线程同时操作

处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程在再使用

队列+锁:锁机制(synchronized)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zJT2Wokt-1603259602918)(C:\Users\Wv587-h\AppData\Roaming\Typora\typora-user-images\image-20201020163000351.png)]

性能倒置

20.三大线程不安全列子

购票;

package safe; public class UnSafeTicket { public static void main(String[] args) { BuyTicket buy=new BuyTicket(); new Thread(buy,"小张").start(); new Thread(buy,"小五").start(); new Thread(buy,"小六").start(); new Thread(buy,"小巴").start(); } } class BuyTicket implements Runnable{ private int tickets=100; private boolean flag=true; @Override public void run() { while (flag){ try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void buy() throws InterruptedException { if (tickets<=0){ flag=false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName()+"拿到第"+tickets--+"票"); } }

取款;

package safe; import com.sun.org.apache.bcel.internal.generic.NEW; import javax.naming.Name; public class UnSafeBank { public static void main(String[] args) { Account account= new Account("联邦",9999999); Bank bank=new Bank(account,5111111); Bank bank2=new Bank(account,5111111); Thread t=new Thread(bank,"多多"); t.start(); Thread t2=new Thread(bank2,"零零"); t2.start(); } } class Account{ private String account; private int money; public Account(String account, int money) { this.account = account; this.money = money; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } class Bank implements Runnable{ Account account; int drawMoney; int nowMoney; public Bank(Account account, int drawMoney) { this.account = account; this.drawMoney = drawMoney; } @Override public void run() { if (account.getMoney()-drawMoney<0){ System.out.println("余额不足!!!"); return; } try { Thread.sleep(1000);//等待让两个线程都进来 } catch (InterruptedException e) { e.printStackTrace(); } account.setMoney(account.getMoney()-drawMoney); nowMoney=nowMoney+drawMoney; System.out.println(Thread.currentThread().getName()+"取走了"+nowMoney); System.out.println(account.getAccount()+"卡上余额为:"+account.getMoney()); } }

集合list;

package safe; import java.util.ArrayList; import java.util.List; public class UnsafeList { public static void main(String[] args) throws InterruptedException { List<String> list=new ArrayList<String>(); for (int i = 0; i < 10010; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } Thread.sleep(1000); System.out.println(list.size()); } }

21.synchronized

同步方法

package safe; public class SafeTicket { public static void main(String[] args) { BuyTicket1 buy=new BuyTicket1(); new Thread(buy,"小张").start(); new Thread(buy,"小五").start(); new Thread(buy,"小六").start(); new Thread(buy,"小巴").start(); } } class BuyTicket1 implements Runnable{ private int tickets=100; private boolean flag=true; @Override public void run() { while (flag){ try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } //在方法加synchronized private synchronized void buy() throws InterruptedException { if (tickets<=0){ flag=false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName()+"拿到第"+tickets--+"票"); } }

同步块

package safe; public class SafeBank { public static void main(String[] args) { Account1 account= new Account1("联邦",9999999); Bank1 bank=new Bank1(account,5111111); Bank1 bank2=new Bank1(account,5111111); Thread t=new Thread(bank,"多多"); t.start(); Thread t2=new Thread(bank2,"零零"); t2.start(); } } class Account1{ private String account; private int money; public Account1(String account, int money) { this.account = account; this.money = money; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } class Bank1 implements Runnable{ Account1 account; int drawMoney; int nowMoney; public Bank1(Account1 account, int drawMoney) { this.account = account; this.drawMoney = drawMoney; } @Override public void run() { //同步块,锁 变化的对象 synchronized(account){ //锁的对象就是变化的量,需要增删改 if (account.getMoney()-drawMoney<0){ System.out.println("余额不足!!!"); return; } try { Thread.sleep(1000);//等待让两个线程都进来 } catch (InterruptedException e) { e.printStackTrace(); } account.setMoney(account.getMoney()-drawMoney); nowMoney=nowMoney+drawMoney; System.out.println(Thread.currentThread().getName()+"取走了"+nowMoney); System.out.println(account.getAccount()+"卡上余额为:"+account.getMoney()); } } }

对比JUC

package safe; import java.util.concurrent.CopyOnWriteArrayList; //测试JUC安全类型的集合 public class TestJUC { public static void main(String[] args) throws InterruptedException { CopyOnWriteArrayList<String> co=new CopyOnWriteArrayList<String>(); for (int i = 0; i < 1000; i++) { new Thread(()->{ co.add(Thread.currentThread().getName()); }).start(); } Thread.sleep(2000); System.out.println(co.size()); } }

22.死锁

多个线程各自占有一些资源,并且互相等待其他线程占有的资源才能运行,而导致两个过着多个线程都在等待对方释放资源,都停止执行的情况 package thread; //多个资源互相抱着对方的资源,形成僵持 public class DeadLock { public static void main(String[] args) { Makeup makeup=new Makeup(0,"小红"); Makeup makeup1=new Makeup(1,"大蓝"); makeup.start(); makeup1.start(); } } class Lipstick{ } class Mirror{ } class Makeup extends Thread{ //static确保资源唯一 static private Lipstick lipstick=new Lipstick(); static private Mirror mirror=new Mirror(); int choose; String name; public Makeup(int choose, String name) { this.choose = choose; this.name = name; } public void run(){ try { makeup(); } catch (InterruptedException e) { e.printStackTrace(); } } private void makeup() throws InterruptedException { if (choose==0){ synchronized (lipstick){ System.out.println(this.name+"拿到口红!!"); Thread.sleep(1000); synchronized (mirror){ System.out.println(this.name+"拿到镜子!!!"); } } /*synchronized (mirror){ System.out.println(this.name+"拿到镜子!!!"); }*/ }else { synchronized (mirror){ System.out.println(this.name+"拿到镜子!!"); Thread.sleep(2000); synchronized (lipstick){ System.out.println(this.name+"拿到口红!!!"); } } /* synchronized (lipstick){ System.out.println(this.name+"拿到口红!!!"); }*/ } } } 产生死锁的四个必要条件 互斥条件:一个资源每次只能被一个进程使用。请求与保持条件:一个进程因请求资源而阻塞是,对已获得的资源保持不放。不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺。循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

上面列出的四个条件,只要想办法破其中的任意一个或多个就可以避免死锁发生

23.Lock

从JDK5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当

java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。

锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

Lock的使用

测试代码

package safe; import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(String[] args) { TicketLock ti=new TicketLock(); new Thread(ti).start(); new Thread(ti).start(); new Thread(ti).start(); } } class TicketLock implements Runnable{ int ticket=10; private final ReentrantLock lock=new ReentrantLock();//创建锁对象 @Override public void run() { while (true) { try { lock.lock();//加锁 if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticket--); } else { return; } } finally { lock.unlock();//解锁 } } } }

synchronized与Lock的对比

Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁,出了作用域自动释放

Lock只有代码块锁,synchronized有代码块锁和方法锁

使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

优先使用顺序:

Lock >同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)

24.生产者消费者

代码

package safe; import java.util.LinkedList; public class TestPC { //最大容量 public static final int MAX_SIZE = 10; //存储媒介 public static LinkedList<Integer> list = new LinkedList<>(); class Producer implements Runnable { @Override public void run() { synchronized (list) { //仓库容量已经达到最大值 while (list.size() == MAX_SIZE) { System.out.println("仓库已满,生产者" + Thread.currentThread().getName() + "不可生产."); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } list.add(1); System.out.println("生产者" + Thread.currentThread().getName() + "生产, 仓库容量为" + list.size()); list.notify(); } } } class Consumer implements Runnable { @Override public void run() { synchronized (list) { while (list.size() == 0) { System.out.println("仓库为空,消费者" + Thread.currentThread().getName() + "不可消费."); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } list.removeFirst(); System.out.println("消费者" + Thread.currentThread().getName() + "消费,仓库容量为" + list.size()); list.notify(); } } } public static void main(String[] args) { TestPC pc = new TestPC(); Producer producer = pc.new Producer(); Consumer consumer = pc.new Consumer(); for (int i = 0; i < 10; i++) { Thread pro = new Thread(producer,"P"); pro.start(); Thread con = new Thread(consumer,"C"); con.start(); } } }

25.线程池

使用线程池

代码

package thread; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPool { public static void main(String[] args) { //创建服务,创建线程池,newFixedThreadPool,参数:个数 ExecutorService service= Executors.newFixedThreadPool(5); service.execute(new MyThread1()); service.execute(new MyThread1()); service.execute(new MyThread1()); service.execute(new MyThread1()); service.execute(new MyThread1()); //关闭服务 service.shutdown(); } } class MyThread1 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }

26.总结

三种方法

package thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; public class ThreadNew { public static void main(String[] args) throws ExecutionException, InterruptedException { //1 Thread1 t1=new Thread1(); t1.start(); //2. Thread2 t2=new Thread2(); new Thread(t2).start(); FutureTask<Integer> task=new FutureTask<Integer>(new Thread3()); new Thread(task).start(); Integer integer=task.get(); System.out.println(integer); } } //1.继承Thread class Thread1 extends Thread{ public void run(){ System.out.println("Thread111"); } } //2.实现Runnable class Thread2 implements Runnable{ @Override public void run() { System.out.println("thread222"); } } //3.实现Callable class Thread3 implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("thread3333"); return 100; } }
最新回复(0)