程序、进程和线程 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。 进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是 CPU 调度和执行的的单位。
普通方法调用和多线程启动
注意:很多多线程是模拟出来的,真正的多线程是指有多个 CPU(多核),如服务器。如果是模拟出来的多线程,即在一个 CPU 的情况下,在同一个时间点,CPU 只能执行一个代码,因为切换得很快,所以就有同时执行的错觉。
线程创建 Thread 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package ml.guest997; public class ThreadTest01 extends Thread { public static void main (String [] args) { new ThreadTest01 ().start (); for (int i = 0 ; i < 1000 ; i++) { System.out.println ("使用 main 线程" + i); } } public void run () { for (int i = 0 ; i < 1000 ; i++) { System.out.println ("使用线程" + i); } } }
可以从图中部分结果看出两个线程是交替执行的,如果将上面代码的 start() 改成 run(),就只是普通地调用方法,而并没有开启线程,会先执行完 run(),再执行后面的代码。
多线程下载图片 添加依赖 1 2 3 4 5 <dependency > <groupId > commons-io</groupId > <artifactId > commons-io</artifactId > <version > 2.11.0</version > </dependency >
代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package ml.guest997;import org.apache.commons.io.FileUtils;import java.io.File;import java.io.IOException;import java.net.URL;public class ThreadTest02 extends Thread { private String url; private String FileName; public ThreadTest02 (String url, String FileName) { this .url = url; this .FileName = FileName; } public static void main (String[] args) { for (int i = 0 ; i < 5 ; i++) { new ThreadTest02("https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto" , "bg" + i + ".png" ).start(); } } @Override public void run () { ImagesDownloader imagesDownloader = new ImagesDownloader(); try { imagesDownloader.downloader(url, FileName); System.out.println(FileName + "下载完成" ); } catch (IOException e) { e.printStackTrace(); } } class ImagesDownloader { public void downloader (String link, String filename) throws IOException { try { URL url = new URL(link); url.openConnection().setRequestProperty("User-Agent" , "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)" ); FileUtils.copyURLToFile(url, new File(filename)); } catch (IOException e) { e.printStackTrace(); } } } }
Runnable 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package ml.guest997;public class ThreadTest03 implements Runnable { @Override public void run () { for (int i = 0 ; i < 1000 ; i++) { System.out.println("使用线程" + i); } } public static void main (String[] args) { new Thread(new ThreadTest03()).start(); for (int i = 0 ; i < 1000 ; i++) { System.out.println("使用 main 线程" + i); } } }
多线程买火车票 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package ml.guest997;public class ThreadTest04 implements Runnable { private int tickets = 100 ; @Override public void run() { while (true ) { if (tickets > 0 ) { System.out.println(Thread.currentThread().getName() + "拿到了第" + tickets-- + "张票" ); continue ; } break ; } } public static void main(String [] args) { ThreadTest04 threadTest04 = new ThreadTest04 (); new Thread (threadTest04,"01" ).start(); new Thread (threadTest04,"02" ).start(); new Thread (threadTest04,"03" ).start(); } }
由于 OOP 的单继承局限性,所有推荐使用 Runnable 实现多线程,更加灵活,方便一个对象能被多个线程使用。
龟兔赛跑 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package ml.guest997; public class ThreadTest05 implements Runnable { private int race = 50 ; private String winner; @Override public void run() { for (int i = 0 ; i <= race; i++) { if (Thread . currentThread() .getName() .equals("兔子" ) & i == 25 ) { try { Thread . sleep(1 ); } catch (InterruptedException e) { e.printStackTrace() ; } } boolean gameOver = gameOver(i ) ; if (gameOver) { break; } System . out.println(Thread . currentThread() .getName() + "跑了" + i + "米" ); } } private boolean gameOver(int already ) { if (winner != null) { System . out.println("已经存在胜利者" ); return true ; } else { if (already >= race) { winner = Thread . currentThread() .getName() ; System . out.println("胜利者是:" + winner); return true ; } else { return false ; } } } public static void main(String[] args) { ThreadTest05 threadTest05 = new ThreadTest05() ; new Thread(threadTest05 ,"兔子" ) .start() ; new Thread(threadTest05 ,"乌龟" ) .start() ; } }
Callable 多线程下载图片 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package ml.guest997;import org.apache.commons.io.FileUtils;import java.io.File;import java.io.IOException;import java.net.URL;import java.util.concurrent.*;public class ThreadTest06 implements Callable <Boolean > { private String url; private String FileName; public ThreadTest06(String url, String FileName) { this .url = url; this .FileName = FileName; } public static void main(String [] args) throws ExecutionException, InterruptedException { ThreadTest06 t1 = new ThreadTest06 ("https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto" , "bg0.png" ); ThreadTest06 t2 = new ThreadTest06 ("https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto" , "bg1.png" ); ThreadTest06 t3 = new ThreadTest06 ("https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto" , "bg2.png" ); FutureTask<Boolean> futureTask1 = new FutureTask <>(t1); FutureTask<Boolean> futureTask2 = new FutureTask <>(t2); FutureTask<Boolean> futureTask3 = new FutureTask <>(t3); new Thread (futureTask1).start(); new Thread (futureTask2).start(); new Thread (futureTask3).start(); System.out.println(futureTask1.get ()); System.out.println(futureTask2.get ()); System.out.println(futureTask3.get ()); } @Override public Boolean call() { ThreadTest06.ImagesDownloader imagesDownloader = new ThreadTest06 .ImagesDownloader(); try { imagesDownloader.downloader(url, FileName); System.out.println(FileName + "下载完成" ); } catch (IOException e) { e.printStackTrace(); } return true ; } class ImagesDownloader { public void downloader(String link, String filename) throws IOException { try { URL url = new URL (link); url.openConnection().setRequestProperty("User-Agent" , "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)" ); FileUtils.copyURLToFile(url, new File (filename)); } catch (IOException e) { e.printStackTrace(); } } } }