多线程
线程简介
Process 和 Thread(进程和线程)
-
进程包含多个线程
-
即使自己没有创建线程,后台也会有多个线程,如主线程,GC线程(Garbage Collection)
-
-
线程是CPU调度和执行的基本单位
-
main()称之为主线程,为系统的入口,用于执行整个程序
-
线程的运行和调度器安排调度,调度器是与os紧密相关的,先后顺序不能人为干预
-
-
模拟多线程(单核但是切换快,感觉像是同时运行)
-
真正的多线程(多核)
-
对同一份资源操作时,会存在资源抢夺,需要并发控制
-
线程的使用需要额外开销(CPU调度时间,并发控制开销)
-
线程有自己的工作内存,内存控制不当会造成数据不一致
-
线程创建
-
继承Thread类
-
Runnable接口
-
Callable接口
Thread类
继承Thread类
重写run()方法
调用start开启线程
package com.wang.Thread;
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
//线程开启不一定立即执行,由CPU调度执行
public class TestThread1 extends Thread {
public void run(){
//run方法体
for (int i = 0; i < 200; i++){
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
//main 线程,主线程
TestThread1 testThread1 = new TestThread1();
//调用start方法开启线程
testThread1.start();
for (int i = 0; i < 200; i++){
System.out.println("我在学习多线程"+i);
}
}
}
Runnable
Runnable接口
实现Runnable接口
重写run方法
将runnable接口的对象丢入接口
package com.wang.Thread;
//创建线程方式二 实现runnable接口,重写run方法
//执行线程丢入接口,调用start()
public class TestThread3 implements Runnable{
//重写run方法
public void run(){
//run方法体
for (int i = 0; i < 200; i++){
System.out.println("我在看代码"+i);
}
}
//main 线程,主线程
public static void main(String[] args) {
//新建runnable接口的实现类对象
TestThread3 testThread1 = new TestThread3();
//新建线程的对象,参数为runnable对象
Thread thread = new Thread(testThread1);
//调用start方法开启线程
thread.start();
for (int i = 0; i < 200; i++){
System.out.println("我在学习多线程"+i);
}
}
}
-
避免了单继承局限性,灵活方便,方便同一个对象被多个线程使用(推荐使用)
案例:龟兔赛跑
package com.wang.Thread;
//模拟龟兔赛跑
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%20==0){
try {
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
}
if (gameOver(i)){
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 true;
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
Callable(了解即可)
-
需要返回值类型
-
重写call方法,需要抛出异常
package com.wang.Thread.Demo01;
import com.wang.Thread.TestThread2;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
//实现callable接口
public class TestCallable implements Callable<Boolean> {
private String url;//网络图片地址
private String name;//保存的文件名
public TestCallable(String url,String name){
this.name = name;
this.url = url;
}
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下载的文件名为:"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testThread1 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou1");
TestCallable testThread2 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou2.jpg");
TestCallable testThread3 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou3");
TestCallable testThread4 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou4");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(4);
//提交执行
Future<Boolean> r1 = ser.submit(testThread1);
Future<Boolean> r2 = ser.submit(testThread2);
Future<Boolean> r3 = ser.submit(testThread4);
Future<Boolean> r4 = ser.submit(testThread4);
//获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
boolean rs4 = r4.get();
//关闭服务
ser.shutdown();
}
}
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
}catch (IOException e){
e.printStackTrace();
System.out.println("IO异常,downloader方法");
}
}}
静态代理
-
真实对象和代理对象都要实现同一个接口
-
代理对象要代理真实角色
-
代理对象可以做很多真实对象做不了的事情
-
真实对象专注做自己的事情
package com.wang.proxy;
public class StaticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany = new WeddingCompany(new You());
weddingCompany.HappyMarry();
//Thread代理runnable对象
new Thread(()-> System.out.println("我愿意")).start();
}
}
interface Marry{
//
void HappyMarry();
}
//真实角色,你去结婚
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("结婚了");
}
}
//婚庆公司代理结婚
class WeddingCompany implements Marry{
private Marry target;
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();
after();
}
public WeddingCompany(Marry target){
//真实对象的结婚
this.target = target;
}
private void after(){
System.out.println("收尾款");
}
private void before(){
System.out.println("布置婚礼现场");
}
}
Lambda表达式
避免匿名内部类定义过多
代码看起来更简洁
去掉了一堆无意义的代码,只留下核心逻辑
函数式接口
-
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
-
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
lambda的优化过程:
package com.wang.lambda;
/*
推到lambda表达式
*/
public class TestLambda01 {
//3.用静态内部类实现方法
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("lambda3");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类,没有类的名称,必须借助接口或者父类,此例中ILike就是接口
ILike like5 = new ILike() {
@Override
public void lambda() {
System.out.println("lambda4");
}
};
like5.lambda();
//用lambda简化,接口只有一个类且只有一个方法
like = ()-> {
System.out.println("lambda5");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface ILike{
void lambda();
}
//2.实现接口
class Like implements ILike{
@Override
public void lambda() {
System.out.println("lambda");
}
}
package com.wang.lambda;
public class TestLambda02 {
public static void main(String[] args) {
Ilove ilove = (int a)->{
System.out.println("I LOVE U"+a);
};
//lambda简化 1 参数类型可消去
Ilove love = (a)->{
System.out.println("OOOO");
};
//简化 2 括号可去
Ilove love2 = a->{
System.out.println("QQQQQ"+a);
};
//简化 3 去掉花括号
Ilove love3 = a-> System.out.println("QQQQQ"+a);
love3.love(521);
//总结:
//多行就带上花括号,单行功能才能去掉花括号
//函数式接口才可以用lambda接口
//多参数必须要带括号
//
}
}
interface Ilove{
void love(int a);
}
线程的切换

Java多线程详解:创建、并发控制与线程安全
本文详细介绍了Java中的线程概念,包括进程与线程的关系、线程的调度执行以及模拟多线程。通过继承Thread类、实现Runnable接口和Callable接口三种方式创建线程,并展示了线程同步与并发控制的重要性。同时,通过实例展示了静态代理和Lambda表达式的应用,强调其在多线程编程中的作用。最后,探讨了线程切换的原理和注意事项。
181

被折叠的 条评论
为什么被折叠?



