回顾一下多线程-壹
main()为主线程,系统的入口
一个进程中,如果开辟了多个线程,线程的运行由调度器安排,调度器是与操作系统紧密相关的,先后顺序是不能认为干预的(无法预测线程运行顺序)
程序运行时,默认会有多个线程,比如 main 和 gc(垃圾回收器) 等等
Maven 自动导入 jar 包
比如我们要用 Maven 导入 Apache 的 commons-io
然后选择一个版本点进去
复制框里的内容,找到 Java 项目pom.xml
文件,粘贴到如下地方
然后右键pom.xml
->Maven->重新加载项目.
在 VScode 内的话也有这种操作:
当然关闭然后重新打开 IDE 也是可以的,Maven 会自动更新,更新后如下,包就导进来了:
多线程实现-并行下载
extends-Thread
public class Downloader1 extends Thread { private String url; private String fileName;
public Downloader1(String url, String fileName) { this.url = url; this.fileName = fileName; }
@Override public void run() { try { FileUtils.copyURLToFile(new URL(url), new File(fileName)); System.out.println("Downloader1 is running"); } catch (IOException e) { e.printStackTrace(); } }
public static void main(String[] args) { new Downloader1("https://pan.weidows.tech/d/local/img/divider.png", "divider.png").start(); } }
|
implements-Runnable-最常用
package twenty.november.thread.downloader;
import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL;
import org.apache.commons.io.FileUtils;
public class Downloader implements Runnable { private String url; private String fileName;
public Downloader(String url, String fileName) { this.url = url; this.fileName = fileName; }
@Override public void run() { try { FileUtils.copyURLToFile(new URL(url), new File(fileName)); System.out.println("Download finished."); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
public static void main(String[] args) { new Thread(new Downloader("https://pan.weidows.tech/d/local/img/divider.png", "./1.png")).start(); new Thread(new Downloader("https://pan.weidows.tech/d/local/img/divider.png", "./2.png")).start(); } }
|
implements-Callable
Callable 与 Runnable 区别为它可以带有返回值类型,可以抛出异常
package twenty.november.thread.downloader;
import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;
import org.apache.commons.io.FileUtils;
public class Downloader2 implements Callable<Object> { private String url; private String fileName;
@Override public Object call() throws MalformedURLException, IOException { FileUtils.copyURLToFile(new URL(url), new File(fileName)); System.out.println(fileName + "下载完成"); return null; }
public Downloader2(String url, String fileName) { this.url = url; this.fileName = fileName; }
public static void main(String[] args) { ExecutorService ser = Executors.newFixedThreadPool(2);
Future<Object> submit1 = ser .submit(new Downloader2("https://pan.weidows.tech/d/local/img/divider.png", "./1.png")); Future<Object> submit2 = ser .submit(new Downloader2("https://pan.weidows.tech/d/local/img/divider.png", "./2.png"));
try { Object result1 = submit1.get(); Object result2 = submit2.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
ser.shutdown(); } }
|
静态代理
package twenty.november.proxy.static_proxy;
public class StaticProxy { public static void main(String[] args) { MarryProxy proxy = new MarryProxy(new Me("Weidows")); proxy.Marry(); } }
interface Marry { void Marry(); }
class Me implements Marry { public String name;
@Override public void Marry() { System.out.println(name + "结婚了"); }
public Me(String name) { this.name = name; }
}
class MarryProxy implements Marry { private Me target;
@Override public void Marry() { before(); target.Marry(); after(); }
private void after() { System.out.println(target.name + "结婚后"); }
private void before() { System.out.println(target.name + "结婚前"); }
public MarryProxy(Me target) { this.target = target; }
}
|
生命周期-线程状态
public class TestState { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("///"); });
Thread.State state = thread.getState(); System.out.println(state);
thread.start(); state = thread.getState(); System.out.println();
while (state != Thread.State.TERMINATED) { Thread.sleep(100); state = thread.getState(); System.out.println(state);
} } }
|
Thread-操作
如何停止线程
- 利用循环计数,不建议死循环
- 使用标志位——>设置一个标志位
不要用
stop 或者 destroy 等 JDK-deprecated 的方法
public class TestStop implements Runnable { private boolean flag = true;
@Override public void run() { int i = 0; while (flag) { System.out.println("Thread.run()运行次数: " + i++); } }
public void stop() { this.flag = false; }
public static void main(String[] args) { TestStop testStop = new TestStop(); new Thread(testStop).start();
for (int i = 0; i < 100; i++) { System.out.println("main: " + i); if (i == 90) { testStop.stop(); System.out.println("testStop线程停止了,main线程还在运行"); } } } }
|
线程休眠-sleep
public class TestSleep { public static void main(String[] args) { try { tenSecondsDown();
countTime(); } catch (InterruptedException e) { e.printStackTrace(); } }
public static void tenSecondsDown() throws InterruptedException { int num = 10; while (true) { Thread.sleep(1000); System.out.println(num--); if (num == 0) break; } }
public static void countTime() { Date startTime = new Date(System.currentTimeMillis()); while (true) { try { System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
线程让步-yield
public class TestYield { public static void main(String[] args) {
Runnable myYield = () -> { System.out.println(Thread.currentThread().getName() + "线程开始执行"); Thread.yield(); System.out.println(Thread.currentThread().getName() + "线程停止执行"); };
new Thread(myYield, "a").start(); new Thread(myYield, "b").start(); } }
|
结果
a线程开始执行 b线程开始执行 a线程停止执行 b线程停止执行
|
- 让步未成功(但也并不能认为是失败,确确实实让了一下)
a线程开始执行 a线程停止执行 b线程开始执行 b线程停止执行
|
线程插队-Join
public class TestJoin { public static void main(String[] args) throws InterruptedException { Runnable testJoin = () -> { for (int i = 0; i < 100; i++) { System.out.println("vipThread" + i); } }; Thread vipThread = new Thread(testJoin); vipThread.start();
for (int i = 0; i < 100; i++) { if (i == 50) { vipThread.join(); } System.out.println("main" + i); } } }
|
- 结果
main0 vipThread0 main1 vipThread1 vipThread2 main2 main3 vipThread3 main4 vipThread4 main5 vipThread5 main6 vipThread6 main7 vipThread7 main8 vipThread8 main9 vipThread9 main10 vipThread10 main11 vipThread11 main12 vipThread12 main13 vipThread13 main14 vipThread14 main15 vipThread15 main16 vipThread16 main17 vipThread17 main18 vipThread18 main19 main20 vipThread19 main21 vipThread20 vipThread21 main22 vipThread22 main23 vipThread23 main24 main25 vipThread24 main26 main27 vipThread25 vipThread26 main28 main29 vipThread27 main30 vipThread28 main31 main32 vipThread29 vipThread30 main33 vipThread31 vipThread32 vipThread33 main34 vipThread34 main35 main36 vipThread35 vipThread36 main37 vipThread37 main38 vipThread38 main39 vipThread39 vipThread40 main40 vipThread41 main41 vipThread42 main42 vipThread43 main43 vipThread44 main44 vipThread45 main45 vipThread46 main46 vipThread47 main47 vipThread48 main48 vipThread49 main49 vipThread50 vipThread51 vipThread52 vipThread53 vipThread54 vipThread55 vipThread56 vipThread57 vipThread58 vipThread59 vipThread60 vipThread61 vipThread62 vipThread63 vipThread64 vipThread65 vipThread66 vipThread67 vipThread68 vipThread69 vipThread70 vipThread71 vipThread72 vipThread73 vipThread74 vipThread75 vipThread76 vipThread77 vipThread78 vipThread79 vipThread80 vipThread81 vipThread82 vipThread83 vipThread84 vipThread85 vipThread86 vipThread87 vipThread88 vipThread89 vipThread90 vipThread91 vipThread92 vipThread93 vipThread94 vipThread95 vipThread96 vipThread97 vipThread98 vipThread99 main50 main51 main52 main53 main54 main55 main56 main57 main58 main59 main60 main61 main62 main63 main64 main65 main66 main67 main68 main69 main70 main71 main72 main73 main74 main75 main76 main77 main78 main79 main80 main81 main82 main83 main84 main85 main86 main87 main88 main89 main90 main91 main92 main93 main94 main95 main96 main97 main98 main99
|
- 可以见到 main 和 vipThread 两个线程几乎同步执行,到了 main49 时,vipThread 会主动插队,这时 vipThread 之外的线程阻塞.
线程优先级-Priority
线程的优先级用数字表示,范围从 1~10.
- Thread.MIN_PRIORITY = 1;
- Thread.MAX_PRIORITY = 10;
- Thread.NORM_PRIORITY = 5;
使用一下方法改变或获取优先级
- .getPriority()
- .setPriority(int xxx)
不做举例了.
守护线程-daemon
线程分为用户线程
和守护线程
,用户线程必须执行完毕程序才终止,而守护线程不做要求.
public class TestDaemon { public static void main(String[] args) { Thread godThread = new Thread(() -> { while (true) { System.out.println("上帝保佑你"); } }); godThread.setDaemon(true); godThread.start();
new Thread(() -> { for (int i = 0; i < 100; i++) { System.out.println("你一生都开心的活着"); } System.out.println("GoodBye World"); }).start(); } }
|
结果: "you"线程终止后 daemon 线程仍执行了一段时间
... 上帝保佑你 上帝保佑你 你一生都开心的活着 你一生都开心的活着 你一生都开心的活着 你一生都开心的活着 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 上帝保佑你 GoodBye World 上帝保佑你 上帝保佑你
|