实现线程的方式:Thread类重写run();Runnable类重写run();Callable类重写call();实现线程的方式
实现线程的方式
1.继承Thread类重写run();
Thread类中常用的两个构造方法是:
public Thread();//无参构造
public Thread(String threadName);//有参构造
完成线程真正功能的代码放在类的run()方法中,当一个类继承Thread类后,就可以在该类中覆盖run()方法,
将实现该功能的代码写入run()方法中,然后调用Thread类中的start()方法执行线程,等价于调用run()方法;
其中,Thread类不可以重复启动一个线程,也就是说,不可以调用已经启动的线程。强行调用,会抛出异常IllegalTreadStateException。
2.实现Runnable接口重写run();
实际上,Thread类实现了Runnable接口,其中的run()方法就是对Runnable接口中的run()方法的具体实现。
实现Runnable接口的程序会创建一个Thread对象,并将Runnable对象和Thread对象相关联。适合多个相同的程序代码的线程去处理同一个资源。
Thread类有以下两个构造方法:使用这两个方法就可以将Runnable和Thread两个实例相关联。
public Thread(Runnable target);/traget是目标的意思
public Thread(Runnable target,String name);
使用Runnable接口启动线程的步骤:
建立Runnable对象;
使用参数为Runnable对象的构造方法创建Thread实例;
调用start()方法启动线程;
说到这里你可能也不明白怎么整,所以,请看下面的代码:
RET.java
package com;
public class RET implements Runnable {
private static int ticket = 10;
public RET() {
}
@Override
public void run() {//防止线程抢占资源
while(ticket>0) {
synchronized("") {//这样也行,定义锁也行,目前我还没发现这两种的区别,待定!!!!
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"张票");
--ticket;
}else {
System.out.println("票卖完了");
}
}
}
}
}
App.java
package com;
public class App {
public App() {
RET r1 = new RET();
RET r2 = new RET();
new Thread(r1).start();
new Thread(r2).start();
new Thread(r2).start();//可以调用已经启动的线程,虽然可以这样,但是这条线程算是第三条线程了。不过不建议这样用,因为很混乱。
}
public static void main(String[] args) {
new App();
}
}
其中,如果一个类继承Thread,就不可以资源共享。但是如果实现了Runable接口的话,就可以实现资源共享。说到共享资源,就一定会抢占资源!要加锁!
而且,无论是继承Thread还是实现Runnable都不可以给方法加锁eg:public synchronized void run() {//防止线程抢占资源 因为这样加锁顶不住!!
都要static Object lock="locked";//这样加锁!!!!在改变数据的时候要synchronized(lock){在这里改变数据}!!!!
3.实现Callable接口重写call();
Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。
Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能
Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
步骤:
自定义一个类实现java.util.concurrent包下的Callable接口
重写call方法
将要在线程中执行的代码编写在call方法中
创建ExecutorService线程池
将自定义类的对象放入线程池里面
获取线程的返回结果
关闭线程池,不再接收新的线程,未执行完的线程不会被关闭
看代码:
call.java
package com;
import java.util.concurrent.Callable;
public class call implements Callable<String> {//定义一个类实现Callable<V>接口
private static int ticket = 10;
private Object lock = "";
public call() {
}
@Override
public String call() throws Exception {
while(ticket>0) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName()+"第"+ticket+"张");
--ticket;
}
}
return "没错,我执行完了上面的代码,还告诉你我完事了。";
}
}
App.java
package com; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class App { public App() { //创建ExecutorService线程池 ExecutorService threadPool = Executors.newSingleThreadExecutor(); //创建存储Future对象,用来存放ExecutorService的执行结果 Future<String> future = threadPool.submit(new call()); try { System.out.println("等待线程结束"); System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); }finally{
threadPool.shutdown();
}
}
public static void main(String[] args) {
new App();
}
}

但是,线程池怎么可能只放一个线程呢??请看多个线程的办法,就是存到了数组里
cable.java
package com;
import java.util.concurrent.Callable;
public class cable implements Callable<String> {//定义一个类实现Callable<V>接口
private int a,b;
public cable(int a,int b) {
this.a=a;
this.b=b;
}
@Override
public String call() throws Exception {
System.out.println(a+b+" "+Thread.currentThread().getName());
Thread.sleep(1000);
return "没错,我执行完了上面的代码,还告诉你我完事了。";
}
}
App.java
package com;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class App {
public App() throws InterruptedException, ExecutionException {
//创建ExecutorService线程池
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//创建存储Future对象的集合,用来存放ExecutorService的执行结果
ArrayList<Future<String>> future = new ArrayList<Future<String>>();
//举例子:开3个线程,将返回的Future对象放入集合中
future.add(threadPool.submit(new cable(1,2)));
future.add(threadPool.submit(new cable(4,5)));
future.add(threadPool.submit(new cable(7,8)));
for (Future<String> fs : future) {
//判断线程是否执行结束,如果执行结束就将结果打印
if (fs.isDone()) {
System.out.println("22222"+fs.get());
} else {
System.out.println("44444"+fs.toString());
}
}
//关闭线程池,不再接收新的线程,未执行完的线程不会被关闭
threadPool.shutdown();
System.out.println("main方法执行结束");
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
new App();
}
}

我想要变得高一点,最好能伸手给你一片天。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步