进程与线程

Process与Thread
- 说起进程就不得不说下程序。程序是指指令和数据的有序集合,本身没有任何运行的含义,是一个静态的概念。
- 而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位
- 通常在一个进程中可以包含多个线程,当然一个进程至少有一个线程,不然没有存在的意义。显示CPU调度和执行的单位
注意:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能执行一个代码,因为切换的快,所以就有同时执行的错觉
线程的创建
- Thread、Runnable、Callable
- 继承Thread


package com.xy.Test;import org.apache.commons.io.FileUtils;import java.io.File;import java.io.IOException;import java.net.URL;// 练习Thread、实现多线程public class Test02 extends Thread {private String url;private String name;public Test02(String url, String name) {this.url = url;this.name = name;}@Overridepublic void run() {WebDownload webDownload = new WebDownload();webDownload.downloader(url, name);System.out.println("下载的图片名字为: " + name);}public static void main(String[] args) {Test02 t2 = new Test02("<url>", "apache1");Test02 t3 = new Test02("<url>", "apache2");t1.start();t2.start();t3.start();}}// 下载类class WebDownload {// 下载方法public void downloader(String url, String name) {try {FileUtils.copyURLToFile(new URL(url), new File(name));} catch (IOException e) {e.printStackTrace();}}}
- 实现Runnable接口 ```java package com.xy.Test;
// 创建方法二: 实现Runnable接口,重写run方法,执行线程需要丢入runnable接口实现类 // 调用start方法 public class Test03 implements Runnable{
@Overridepublic void run() {for (int i = 0; i < 200; i++) {System.out.println("run线程" + i);}}public static void main(String[] args) {// 创建runnable接口的实现类对象Test03 t1 = new Test03();// 创建线程对象,通过线程对象来开启我们的线程代理Thread thread = new Thread(t1);thread.start();for (int i = 0; i < 100; i++) {System.out.println("主线程" + i);}}
}
```javapackage com.xy.Test;// 多个线程同时操作同一个对象// 买火车票的例子// 多个线程操作同一个资源的情况下,线程不安全,数据混乱public class Test04 implements Runnable{private int ticketNums = 10;@Overridepublic void run() {while (true) {if (ticketNums <= 0) {break;}try {Thread.sleep(200);}catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "拿到了第几张:" + ticketNums-- + "票");}}public static void main(String[] args) {Test04 test04 = new Test04();new Thread(test04, "小明").start();new Thread(test04, "老师").start();new Thread(test04, "黄牛").start();}}
package com.xy.Test;// 模拟龟兔赛跑public class Race implements Runnable {// 胜利者public static String winner;@Overridepublic void run() {for (int i = 0; i <= 100; i++) {// 模拟兔子休息if ((Thread.currentThread().getName().equals("兔")) && (i == 20)) {try {Thread.sleep(1);}catch (InterruptedException e) {e.printStackTrace();}}// 判断比赛是否结束boolean flag = gameOver(i);if(flag) {break;}else {}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 true;}}return false;}public static void main(String[] args) {Race race = new Race();new Thread(race, "兔").start();new Thread(race, "龟").start();}}
- 实现Callable接口 ```java package com.xy.Test;
import com.sun.org.apache.xpath.internal.operations.Bool; import org.apache.commons.io.FileUtils;
import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.*;
// 练习Thread、实现多线程
public class TestCallable implements Callable
private String url;private String name;public TestCallable(String url, String name) {this.url = url;this.name = name;}@Overridepublic Boolean call() {WebDownload1 webDownload1 = new WebDownload1();webDownload1.downloader(url, name);System.out.println("下载的图片名字为: " + name);return true;}public static void main(String[] args) throws ExecutionException, InterruptedException {TestCallable t1 = new TestCallable("https://images.unsplash.com/photo-1650844565749-1f10c8aaa9f9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80", "apache");TestCallable t2 = new TestCallable("https://images.unsplash.com/photo-1650844565749-1f10c8aaa9f9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80", "apache1");TestCallable t3 = new TestCallable("https://images.unsplash.com/photo-1650844565749-1f10c8aaa9f9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80", "apache2");// 创建执行服务ExecutorService ser = Executors.newFixedThreadPool(3);// 提交执行Future<Boolean> r1 = ser.submit(t1);Future<Boolean> r2 = ser.submit(t2);Future<Boolean> r3 = ser.submit(t3);// 获取结果boolean rs1 = r1.get();boolean rs2 = r2.get();boolean rs3 = r3.get();// 关闭服务ser.shutdownNow();}
}
// 下载类 class WebDownload1 { // 下载方法 public void downloader(String url, String name) { try { FileUtils.copyURLToFile(new URL(url), new File(name)); } catch (IOException e) { e.printStackTrace(); } } }
<a name="R3Wck"></a>## 代理<a name="hZZjy"></a>### 静态代理```javapackage com.xy.proxy;public class StaticProxy {public static void main(String[] args) {WeddingCompany weddingCompany = new WeddingCompany(new You());weddingCompany.HappyMarry();}}interface Marry {void HappyMarry();}// 真实角色class You implements Marry {@Overridepublic void HappyMarry() {System.out.println("你结婚啦");}}// 代理角色class WeddingCompany implements Marry {private Marry target;public WeddingCompany(Marry target) {this.target = target;}@Overridepublic void HappyMarry() {before();this.target.HappyMarry();after();}private void before() {System.out.println("结婚之前布置现场");}private void after() {System.out.println("收尾款");}}
Lamda表达式
- 避免匿名内部类定义过多
其实质属于函数式编程的概念
new Thread(() -> System.out.println("多线程学习")).start();
理解Functional Interface(函数式接口)是学习Java8 lambda表达式的关键所在
- 函数式接口的定义:
- 任何接口,如果包含唯一一个抽象方法,那么它就是一个函数式接口
- 对于函数式接口,我们可以通过lambda表达式来闯将接口的对象 ```java package com.xy.Lambda;
/**
- 推导lambda表达式 */
// 定义一个函数式接口(一个接口,只包含一个抽象方法) interface ILike { void lambda(); }
public class TestLambda { private static ILike like; public static void main(String[] args) { like = () -> { System.out.println(“lambda表达式”); }; like.lambda(); } }
<a name="rRbfR"></a>## 线程状态| 方法 | 说明 || --- | --- || setPriority(int newPriority) | 更改线程的优先级 || static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 || void join() | 等待该线程终止 || static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 || void interrupt() | 中断线程,别用这个方式 || boolean isAlive() | 测试线程是否处于活动状态 |```javapackage com.xy.State;public class Sleep2 {static public void tenDown() {int num = 10;while (true){if (num <= 0) break;try {Thread.sleep(1000);System.out.println(num--);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {tenDown();}}
package com.xy.State;// 测试join方法 、、 插队public class Join implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("线程VIP来了" + i);}}public static void main(String[] args) {// 启动线程Join join = new Join();Thread thread = new Thread(join);thread.start();for (int i = 0; i < 1000; i++) {if(i == 200) {try {thread.join(); // 插队} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("main" + i);}}}
package com.xy.State;// 测试stop// 1.建议线程正常停止 -------> 利用次数,不建议死循环// 2.设置一个标志位 -----> 设置一个标志位// 3.不要使用stop或者destroy等过时或jdk不建议使用的方法public class Stop implements Runnable {// 1. 设置一个标志位private boolean flag = true;@Overridepublic void run() {int i = 0;while (flag) {System.out.println("run....Thread" + i++ );}}//2. 设置一个公开的方法停止线程,转换标志位public void stop() {this.flag = false;}public static void main(String[] args) {Stop stop = new Stop();new Thread(stop).start();for (int i = 0; i < 1000; i++) {System.out.println("main" + i);if (i == 900) {stop.stop();System.out.println("线程停止");}}}}
package com.xy.State;// 线程礼让public class Yield{public static void main(String[] args) {A1 a1 = new A1();new Thread(a1, "a").start();new Thread(a1, "b").start();}}class A1 implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "线程开始执行!");Thread.yield();System.out.println(Thread.currentThread().getName() + "线程停止执行!");}}
线程状态
- NEW
- 尚未启动的线程处于此状态
- RUNNABLE
- 在Java虚拟机中执行的线程处于此状态
- BLOCKED
- 被阻塞等待监视器锁定的线程出于此状态
- WAITING
- 正在等待另一个线程执行特定动作的线程处于此状态
- TIMED_WAITING
- 正在等待另一个线程执特定行动作到达指定等待时间的线程, 处于此状态
- TERMINATED
- 已退出的线程出于此状态
一个线程可以在给定时间点处于一个状态。这些状态是不反应任何操作系统线程状态的虚拟机状态。
package com.xy.State;// 观察测试线程的状态public class State {public static void main(String[] args) {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); // New// 观察启动后thread.start(); // 启动线程state = thread.getState();System.out.println(state); // Runwhile (state != Thread.State.TERMINATED) {// 只要线程不终止,就一直输出状态state = thread.getState();System.out.println(state);}}}
线程优先级
- Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调用哪个线程来执行。
- 线程的优先级用数字表示,范围从1~10
- Thread.MIN_PROIORITY = 1;
- Thread.MAX_PROIORITY = 10;
- Thread.NORM_PROIORITY = 10;
- 使用以下方式改变或获取优先级
- getPriority .setPriority(int XXX) ```java package com.xy.Priority;
public class Priority implements Runnable { @Override public void run(){ System.out.println(Thread.currentThread().getName() + “———->” + Thread.currentThread().getPriority() ); } public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + “———->” + Thread.currentThread().getPriority() ); Priority priority = new Priority(); Thread t1 = new Thread(priority, “t1”); Thread t2 = new Thread(priority, “t2”); Thread t3 = new Thread(priority, “t3”); Thread t4 = new Thread(priority, “t4”); Thread t5 = new Thread(priority); Thread t6 = new Thread(priority);
// 设置优先级再启动t1.start();t2.setPriority(1);t2.start();t3.setPriority(4);t3.start();t4.setPriority(Thread.MAX_PRIORITY);t4.start();}
}
<a name="pYllE"></a>### 守护(daemon)线程- 线程分为**用户线程**和**守护线程**- 虚拟机必须确保用户线程执行完毕- 虚拟机不用等待守护线程执行完毕- 如,后台记录操作日志,监控内存,垃圾回收等待。。。```javapackage com.xy.Priority;// 测试守护线程public class Daemon {public static void main(String[] args) {God god = new God();You you = new You();Thread thread = new Thread(god);thread.setDaemon(true); // 默认为false表示用户线程,正常的线程都是用户线程thread.start(); // 上帝启动new Thread(you).start();}}class God implements Runnable {@Overridepublic void run() {while (true) {System.out.println("上帝保佑你");}}}class You implements Runnable{@Overridepublic void run() {for (int i = 0; i < 36500; i++) {System.out.println("你一生都开心的活着");}System.out.println("====goodbye!====");}}
线程同步
- 并发: 同一个对象被多个线程同时操作

package com.xy;// 线程不安全,有负数public class UnSafe {public static void main(String[] args) {Buy buy = new Buy();new Thread(buy, "w").start();new Thread(buy, "n").start();new Thread(buy, "h").start();}}class Buy implements Runnable {private int tickNums = 15;boolean flag = true;@Overridepublic void run() {while (flag) {try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}private synchronized void buy() throws InterruptedException {if(tickNums <= 0) {flag = false;return;}Thread.sleep(100);System.out.println(Thread.currentThread().getName()+ "拿到了" + tickNums--);}}
死锁
- 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同事拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题。
