Callable接口
步骤
实现callable接口,需要返回值类型
重写call方法,需要抛出异常
创建目标对象
创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(3); //3个线程
提交执行:Future result1=ser.submit(t1);
获取结果:boolean r1=result1.get()
关闭服务:ser.shutdownNow()
好处:
可以定义返回值
可以抛出异常
代码示例
public class TestCallable implements Callable<Boolean> { private String url;//网络图片地址 private String name;//保存文件名称 public TestCallable (String url,String name){ this.url=url; this.name=name; } //下载图片线程的执行体 @Override public Boolean call() throws Exception { WebDownloader webDownloader=new WebDownloader(); webDownloader.downloader(url,name); System.out.println("下载了文件名为:"+name); return true; } public static void main(String[] args) { TestCallable t1=new TestCallable("url地址","1.jpg"); TestCallable t2=new TestCallable("url地址","1.jpg"); TestCallable t3=new TestCallable("url地址","1.jpg"); //创建执行服务 ExecutorService ser=Executors.newFixedThreadPool(3); //提交执行 Future<Boolean> r1=ser.submit(t1); Future<Boolean> r2=ser.submit(t1); Future<Boolean> r3=ser.submit(t1); //关闭服务 ser.shutdownNow(); } }
多线程代码实例----龟兔赛跑
龟兔赛跑实例
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(1); }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 is"+winner); return false; } } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
总结
线程与进程的区别
进程是资源分配的最小单位,线程是CPU调度的最小单位。
一个进程包含一个或多个线程,它们共享进程的资源。
线程更轻量级,切换开销更小。
线程的基本使用
继承Thread类或者实现Runnable接口来创建线程类。
使用start()方法启动线程,而不是直接调用run()。
可以给线程设置优先级、守护线程等。
线程安全与同步
多线程访问共享资源需要考虑线程安全问题。
使用synchronized关键字或者Lock接口来对关键代码段加锁,保证同一时刻只有一个线程执行。
线程通信
wait/notify/notifyAll可以实现不同线程之间的通信。
join方法可以等待其他线程结束。
线程池的使用
线程池可以重用固定数量的线程,避免频繁创建销毁。
使用Executor框架中的线程池可以更好地控制线程池的属性。
常见的多线程问题
死锁、活锁、饥饿等问题及定位与解决。
以上是对多线程的一个基本认识,后续会持续更新~~
有不同见解可以指出一起学习~