文章目录

    • 1、线程简介
    • 2、线程实现
    • 2.1 继承 Thread 类,重写 run 方法
    • 2.2 继承 Runnable 接口,创建 Tread 对象
    • 2.3 实现 Callable 接口(了解)
    • 2.4 Lamda 表达式
    • 2.5 静态代理模式
  • 3、线程的 5 种状态
    • 3.1 线程的一些常用方法
      • 3.1.1 线程休眠——sleep()
      • 3.1.2 线程礼让——yield()
      • 3.1.2 合并线程——Join()
    • 3.2 停止线程的方式
    • 3.3 线程状态观测
    • 3.4 线程优先级
    • 3.5 守护(daemon)线程
    • 3.6 并发
  • 4、线程同步
    • 4.1 线程不安全举例
    • 4.2 同步方法
    • 4.3 同步块
    • 4.3 死锁
    • 4.4 Lock(锁)
  • 5.线程通信
    • 5.1 解决线程之间通信问题的几个方法
    • 5.2 解决线程之间通信的方式1:管程法
    • 5.3 解决线程之间通信的方式1:信号灯法
    • 5.4 使用线程池
    • 6 补充内容
      • 6.1 wait() 方法

1、线程简介

栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过 JVM 的启动参数来进行调整,栈空间用光了会引发 StackOverflowError,而堆和常量池空间不足则会引发 OutOfMemoryError。

String str = new String("hello"); 

上面的语句中变量 str 放在栈上,用 new 创建出来的字符串对象放在堆上,而 “hello” 这个字面量是放在方法区的。

在这里插入图片描述
例子:

开车 + 打电话

吃饭 + 玩手机

这些动作都可以抽象为任务,虽然看起来一心二用,但人只有一个大脑,在一个时间片刻只能处理一个任务。

CPU 也是一样,面对多个任务,只能在一个时间片刻处理一个任务。

主线程调用 run 方法和调用 start 方法开启子线程的区别如下图所示。
在这里插入图片描述

  • 线程就是独立的执行路径;
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,GC 线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预。
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 线程会带来额外的开销,如 CPU 调度时间,并发控制开销。
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

2、线程实现

线程的三种实现方式:

在这里插入图片描述

2.1 继承 Thread 类,重写 run 方法

继承 Thread 类,重写 run 方法。创建这个类的对象,再调用 start() 即可

package com.sjmp.Thread01;/*** @ClassName ThreadTest* @Description TODO* @Author sjmp1573* @Date DATE{TIME}*/
public  class ThreadTest {// 继承 Thread 类并重写 run 方法public static class MyThread extends Thread{@Overridepublic void run() {System.out.println("I am a child thread");}}public static void main(String[] args) {//创建一个线程MyThread thread = new MyThread();//启动线程thread.start();}
}

下载文件需要在 pom.xml 中 commons io 包。

使用该方法下载网络图片。

package com.sjmp.demo01;import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.URL;/*** @author: sjmp1573* @date: 2020/11/15 20:58* @description:*/public class TestThread2 extends Thread{//    网络图片地址private String url;
//    保存的文件名private String name;public TestThread2(String url,String name){this.url = url;this.name = name;}@Overridepublic void run() {
//        进入线程后,会创建一个下载器,下载器通过 downloader 方法,传入 url 和 name 下载相应的资源WebDownloader webDownloader = new WebDownloader();webDownloader.downloader(url,name);System.out.println("下载了文件名为:"+ name);}public static void main(String[] args) {
//        这是 TestThread2 类的主方法
//        创建三个继承 Thread 的子类TestThread2 test01 = new TestThread2("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3796445054,4193265240&fm=26&gp=0.jpg", "test01");TestThread2 test02 = new TestThread2("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605454961548&di=c3b49cc5869f058a6cded1434ea56f85&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F5%2F538ec3134b63b.jpg", "test02");TestThread2 test03 = new TestThread2("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2044644877,1766802492&fm=15&gp=0.jpg", "test03");//        并开启线程test01.start();test02.start();test03.start();}}//下载器,这是一个类
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 方法出现问题");}}
}
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.8.0</version></dependency>

在这里插入图片描述

2.2 继承 Runnable 接口,创建 Tread 对象

继承 Runnable 接口,创建 Tread 对象,传入实现类,开启 start 方法.

package com.sjmp.Thread01;/*** @ClassName ThreadRunnableTest* @Description TODO* @Author sjmp1573* @Date DATE{TIME}*/
public class ThreadRunnableTest {public static class MyThread implements Runnable {@Overridepublic void run() {System.out.println("I am a child thread --Runnable");}}public static void main(String[] args) {MyThread thread = new MyThread();new Thread(thread).start();new Thread(thread).start();}
}

以上两种方式的比较:

继承 Thread 类

  • 子类继承 Thread 类具备多线程能力
  • 启动线程:子类对象 .start()
  • 不建议使用:避免 OOP 单继承局限性

实现 Runnable 接口

  • 实现接口 Runnable 具有多线程能力
  • 启动线程:传入目标对象+Thread对象.start()
  • 推荐使用:避免单继承局限性,方便同一个对象被多个线程使用。

火车抢票实例:

Runnable 实现多线程,创造一个实列 ticketRunnable ,可共享给多个线程。

package com.sjmp.demo01;/*** @author: sjmp1573* @date: 2020/11/15 21:45* @description:*/// 多个线程同时操作同一个对象
//    买火车票的例子
//    发现问题:多个线程操作同一个资源,线程不安全,数据紊乱!public class TicketRunnable implements Runnable{private int ticketNums = 10;@Overridepublic void run() {while (true){if (ticketNums<=0){break;}
//            模拟延时/*IllegalArgumentExceptionif the value of {@code millis} is negative, or the value of{@code nanos} is not in the range {@code 0-999999}InterruptedExceptionif any thread has interrupted the current thread. The<i>interrupted status</i> of the current thread iscleared when this exception is thrown.*/try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}ticketNums--;System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums+"票");}}public static void main(String[] args) {
//        实现了 Runnable 接口的类,创建其实例TicketRunnable ticketRunnable = new TicketRunnable();
//        ticketRunnable 实例可用于多个线程,其中的资源被共享。new Thread(ticketRunnable,"01小明+++++").start();new Thread(ticketRunnable,"02老师-----").start();new Thread(ticketRunnable,"03黄牛=====").start();}
}
"D:\Program Files (x86)\Java\bin\java.exe" "-javaagent:D:\Program Files (x86)\IDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=64250:D:\Program Files (x86)\IDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files (x86)\Java\jre\lib\charsets.jar;D:\Program Files (x86)\Java\jre\lib\deploy.jar;D:\Program Files (x86)\Java\jre\lib\ext\access-bridge-64.jar;D:\Program Files (x86)\Java\jre\lib\ext\cldrdata.jar;D:\Program Files (x86)\Java\jre\lib\ext\dnsns.jar;D:\Program Files (x86)\Java\jre\lib\ext\jaccess.jar;D:\Program Files (x86)\Java\jre\lib\ext\jfxrt.jar;D:\Program Files (x86)\Java\jre\lib\ext\localedata.jar;D:\Program Files (x86)\Java\jre\lib\ext\nashorn.jar;D:\Program Files (x86)\Java\jre\lib\ext\sunec.jar;D:\Program Files (x86)\Java\jre\lib\ext\sunjce_provider.jar;D:\Program Files (x86)\Java\jre\lib\ext\sunmscapi.jar;D:\Program Files (x86)\Java\jre\lib\ext\sunpkcs11.jar;D:\Program Files (x86)\Java\jre\lib\ext\zipfs.jar;D:\Program Files (x86)\Java\jre\lib\javaws.jar;D:\Program Files (x86)\Java\jre\lib\jce.jar;D:\Program Files (x86)\Java\jre\lib\jfr.jar;D:\Program Files (x86)\Java\jre\lib\jfxswt.jar;D:\Program Files (x86)\Java\jre\lib\jsse.jar;D:\Program Files (x86)\Java\jre\lib\management-agent.jar;D:\Program Files (x86)\Java\jre\lib\plugin.jar;D:\Program Files (x86)\Java\jre\lib\resources.jar;D:\Program Files (x86)\Java\jre\lib\rt.jar;E:\SJMP\SpringProject\out\production\LeetCode" com.sjmp.TicketRunnable
03黄牛=====-->拿到了第8票
01小明+++++-->拿到了第8票
02老师------->拿到了第8票
03黄牛=====-->拿到了第7票
02老师------->拿到了第7票
01小明+++++-->拿到了第7票
02老师------->拿到了第6票
03黄牛=====-->拿到了第6票
01小明+++++-->拿到了第6票
01小明+++++-->拿到了第5票
03黄牛=====-->拿到了第4票
02老师------->拿到了第5票
03黄牛=====-->拿到了第3票
02老师------->拿到了第3票
01小明+++++-->拿到了第3票
02老师------->拿到了第1票
03黄牛=====-->拿到了第2票
01小明+++++-->拿到了第2票
02老师------->拿到了第0票
01小明+++++-->拿到了第-1票
03黄牛=====-->拿到了第-1票Process finished with exit code 0

2.3 实现 Callable 接口(了解)

  1. 实现 Callable 接口,需要返回值类型
  2. 重写 call 方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务:ExecutorService = Executor.newFixedThreadPool(1);
  5. 提交执行:Future result1 = ser.submit(1);
  6. 获取结果:boolean r1 = result.get()
  7. 关闭服务:ser.shutdownNow():
package com.sjmp.demo01;import java.util.concurrent.*;/*** @author: sjmp1573* @date: 2020/11/15 22:16* @description:*/public class ThreadByCallable implements Callable<Boolean> {//    网络图片地址private String url;//    保存的文件名private String name;public ThreadByCallable(String url,String name){this.url = url;this.name = name;}@Overridepublic Boolean call() throws Exception {//        进入线程后,会创建一个下载器,下载器通过 downloader 方法,传入 url 和 name 下载相应的资源WebDownloader webDownloader = new WebDownloader();webDownloader.downloader(url,name);System.out.println("下载了文件名为:"+ name);return true;}public static void main(String[] args) throws ExecutionException, InterruptedException {//        这是 TestThread2 类的主方法
//        创建三个继承 Thread 的子类ThreadByCallable test01 = new ThreadByCallable("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3796445054,4193265240&fm=26&gp=0.jpg", "test01");ThreadByCallable test02 = new ThreadByCallable("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605454961548&di=c3b49cc5869f058a6cded1434ea56f85&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F5%2F538ec3134b63b.jpg", "test02");ThreadByCallable test03 = new ThreadByCallable("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2044644877,1766802492&fm=15&gp=0.jpg", "test03");//        创建执行服务:ExecutorService service = Executors.newFixedThreadPool(3);//       提交执行Future<Boolean> submit01 = (Future<Boolean>) service.submit(test01);Future<Boolean> submit02 = (Future<Boolean>) service.submit(test02);Future<Boolean> submit03 = (Future<Boolean>) service.submit(test03);boolean rs1 = submit01.get();boolean rs2 = submit02.get();boolean rs3 = submit03.get();//        关闭服务service.shutdownNow();}
}//下载器,这是一个类
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 方法出现问题");}}
}

--------------------------------------- 华丽的分割线 ----------------------------------------

以下代码来源于《Java 并发编程之美》

CallableTest 类实现了 Callable 接口的 call() 方法。在 main() 函数内首先创建了一个 FutureTask 对象(构造函数为 CallableTest 实例),然后使用创建的 FutureTask 对象作为任务创建了一个线程并且启动它,最后通过 futureTask.get() 等待任务执行完毕返回结果。

public class FutureTask<V> implements RunnableFuture<V>{}public interface RunnableFuture<V> extends Runnable, Future<V>
package com.sjmp.practice;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** @author: sjmp1573* @date: 2021/4/20 21:12* @description:*/public class CallableTest implements Callable<String> {@Overridepublic String call() throws Exception {return "Hello CallableThread";}public static void main(String[] args) {CallableTest callableTest = new CallableTest();FutureTask<String> futureTask = new FutureTask<>(callableTest);new Thread(futureTask).start();try {String s = futureTask.get();System.out.println(s);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}

Hello CallableThreadProcess finished with exit code 0

2.4 Lamda 表达式

Lamda 表达式属于函数式编程的概念

(paraems) -> expressionp[表达式]
(params) -> statement[语句]
(params) -> {statements}
a->System.out.println("i like lamda-->"+a);
new Thread(()->System.out.println("多线程学习...")).start();
  • 理解 Functional Interface(函数式接口)是学习 Java8 Lambda 表达式的关键所在。

  • 函数式接口的定义:

    • 任何接口,如果只包含唯一一个抽象方法,那么它就是函数式接口。
    • 对于函数式接口,可以通过 Lamda 表达式来创建该接口的对象。

Lamda 表达式的演进:

package com.sjmp.demo02;/*** @author: sjmp1573* @date: 2020/11/16 20:11* @description:*/public class LamdaExpression {
//    3.2 实现函数式接口的第二种方法,静态内部类static class Like2 implements ILike{@Overridepublic void lamda() {System.out.println("------3.2 静态内部类实现函数式接口-----");}
}public static void main(String[] args) {//    3.1 实现函数式接口的第一种方法ILike like1 = new Like1();like1.lamda();System.out.println("--3.1 普通方法实现函数式接口--");//    3.2 实现函数式接口的第二种方法,静态内部类new Like2().lamda();//    3.3 局部内部类实现函数式接口class Like3 implements ILike{@Overridepublic void lamda() {System.out.println("------3.3 局部内部类实现函数式接口--------");}}new Like3().lamda();//    3.4 匿名内部类实现函数式接口new ILike() {@Overridepublic void lamda() {System.out.println("------3.4 匿名内部类实现函数式接口----------");}}.lamda();//      3.5 lamda 表达式实现函数式接口ILike like5 = ()->{System.out.println("--3.5 lamda 表达式实现函数式接口--");};like5.lamda();}}// 1. 定义一个函数式接口
interface ILike{void lamda();
}// 2. 实现类
class Like1 implements ILike{@Overridepublic void lamda() {}
}

2.5 静态代理模式

在这里插入图片描述多线程 Thread 为代理,Runnable 为被代理对象:

package com.sjmp.demo02;/*** @author: sjmp1573* @date: 2020/11/16 19:32* @description:*///这是代理
public class StaticProxy implements Marry{private Marry you;public StaticProxy(You you){this.you = you;}public static void main(String[] args) {//        Runnable 是被代理的对象,Thread 是代理/*new Thread(new Runnable() {@Overridepublic void run() {System.out.println("----结婚----");}}).start();*///        使用 lamda 表达式new Thread(()->{System.out.println("----结婚----");}).start();new StaticProxy(new You()).HappyMarry();}@Overridepublic void HappyMarry() {doBefore();you.HappyMarry();doAfter();}public static void doBefore(){System.out.println("-----婚前布置------");}public static void doAfter(){System.out.println("-------婚后收钱-----");}}interface Marry{void HappyMarry();
}
//真实角色,Marryclass You implements Marry{@Overridepublic void HappyMarry() {System.out.println("----- 被代理人 开始结婚------");}
}

3、线程的 5 种状态

  1. 创建
  2. 就绪
  3. 阻塞
  4. 运行
  5. 死亡
    在这里插入图片描述
    在这里插入图片描述

3.1 线程的一些常用方法

线程的一些方法如下图所示:

在这里插入图片描述

3.1.1 线程休眠——sleep()

  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep 存在异常 InterruptedException;
  • sleep 时间达到后线程进入就绪状态;
  • sleep 可以模拟网络延时,倒计时等;
  • sleep 每一个对象都有一个锁,sleep 不会释放锁;

sleep() 方法的用处

package com.sjmp.method;import java.awt.*;
import java.text.SimpleDateFormat;
import java.util.Date;import static java.lang.Thread.*;/*** @author: sjmp1573* @date: 2020/11/16 21:50* @description:*/public class TestSleep {public static void main(String[] args) throws InterruptedException {
//        Thread.sleep()  用于倒计时//        tenStop();//        打印当前系统时间Date date = new Date(System.currentTimeMillis());boolean flag = true;int i = 5;while(flag){if(--i<=0){flag = false;}try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));date = new Date(System.currentTimeMillis());//更新时间}}//    写一个倒计时的方式public static void tenStop() throws InterruptedException {int num = 10;while(true){try{sleep(1000);}catch ( InterruptedException e){e.printStackTrace();}if (num<=0){break;}System.out.println(num--);}}
}

3.1.2 线程礼让——yield()

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞;
  • 将线程从运行状态转为就绪状态;
  • 让 CPU 从新调度,有可能还是调度该礼让线程。
package com.sjmp.method;/*** @author: sjmp1573* @date: 2020/11/16 22:22* @description:*/public class TestYield implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"开启了线程");Thread.yield();System.out.println(Thread.currentThread().getName()+"结束了线程");}public static void main(String[] args) {TestYield testYield = new TestYield();Thread threadA = new Thread(testYield,"threadA");Thread threadB = new Thread(testYield,"threadB");threadA.start();threadB.start();}}

3.1.2 合并线程——Join()

Join 合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞。
可以想象成插队。

package com.sjmp.method;/*** @author: sjmp1573* @date: 2020/11/17 20:46* @description:*/public class TestJoin implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println("Thread : "+i);}}public static void main(String[] args) throws InterruptedException {TestJoin join = new TestJoin();Thread thread = new Thread(join);thread.start();for (int i = 0; i < 200; i++) {if (i==100){thread.join();}System.out.println("main :"+i);}}
}

3.2 停止线程的方式

  • 不推荐使用 JDK 提供的 stop ()、destroy()方法。【已弃用】
  • 推荐线程自己停止下来
  • 建议使用一个标志位进行终止变量 , 当 flag == false,则终止线程运行。
package com.sjmp.demo02;/*** @author: sjmp1573* @date: 2020/11/16 21:33* @description:*/public class ThreadStop implements Runnable{private boolean flag = true;@Overridepublic void run() {int i = 0;while (flag){System.out.println("--- ThreadStop  ---"+i);i++;}}public void stop(){this.flag = false;}public static void main(String[] args) {ThreadStop threadStop = new ThreadStop();Thread thread = new Thread(threadStop);thread.start();for (int i = 0; i < 1000; i++) {if (i==900){threadStop.stop();}System.out.println("--- main ---"+i);}}}

3.3 线程状态观测

Thread.State
线程状态。线程可以处于以下状态之一:

  • NEW
    尚未启动的线程处于此状态。
  • RUNNABLE
    在 Java 虚拟机中执行的线程处于此状态。
  • BLOCKED
    被阻塞等待监视器锁定的线程处于此状态。
  • WAITING
    正在等待另一个线程执行特定动作的线程处于此状态。
  • TERMINATED
    已退出的线程处于此状态。
    一个线程可以在给定时间点处于一个状态。
package com.sjmp.method;/*** @author: sjmp1573* @date: 2020/11/17 21:10* @description:*/public class TestState{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 20; i++) {try {System.out.println(i);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("Thread 执行结束了!");});Thread.State state = thread.getState();System.out.println(state);thread.start();System.out.println(thread.getState());System.out.println(" 我开始循环了 ");while(state != Thread.State.TIMED_WAITING){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}state = thread.getState();System.out.println(state);}}
}

3.4 线程优先级

  • Java 提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
  • 线程的优先级用数字表示,范围从1~10.
    Thread.MIN_PRIORITY=1;
    Thread.MAX_PRIORITY=10;
    Thread.NORM_PRIORITY=5;
  • 使用以下方式改变或获取优先级
    getPriority().setPriority(int xxx)

优先级的设定建议在 start() 调度前

package com.sjmp.method;/*** @author: sjmp1573* @date: 2020/11/17 21:32* @description:*/public class TestPriority implements Runnable {@Overridepublic void run() {System.out.println("当前线程:"+Thread.currentThread().getName());}public static void main(String[] args) {TestPriority runnable = new TestPriority();Thread thread01 = new Thread(runnable,"01");Thread thread02 = new Thread(runnable,"02");Thread thread03 = new Thread(runnable,"03");Thread thread04 = new Thread(runnable,"04");Thread thread05 = new Thread(runnable,"05");thread01.setPriority(Thread.MAX_PRIORITY);thread02.setPriority(7);thread03.setPriority(6);thread04.setPriority(5);thread05.setPriority(4);thread01.start();thread02.start();thread03.start();thread04.start();thread05.start();}
}

3.5 守护(daemon)线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如,后台记录操作日志,监控内存垃圾回收等待…
    在这里插入图片描述
package com.sjmp.method;/*** @author: sjmp1573* @date: 2020/11/17 21:43* @description:*/public class TestsetDaemon {public static void main(String[] args) {God god = new God();You you = new You();Thread thread = new Thread(god);thread.setDaemon(true);thread.start();new Thread(you).start();}
}
class God implements Runnable{@Overridepublic void run() {while (true){System.out.println("Daemoning...");}}
}class You implements Runnable{@Overridepublic void run() {for (int i = 0; i < 365; i++) {System.out.println("living...");}System.out.println("game over---------------------");}
}

3.6 并发

同一个对象被多个线程同时操作

在这里插入图片描述
现实生活中,我们会遇到”同一个资源,多个人都想使用”的问题,比如,食堂排队打饭,每个人都想吃饭,最天然的解决办法就是,排队一个个来。

处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象.这时候我们就需要线程同步.线程同步其实就是一种等待机制,多个需要同时访问!此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。

在这里插入图片描述
形成线程安全的条件:

队列和锁

4、线程同步

由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可.存在以下问题:

  • 一个线程持有锁会导致其他所有需要此锁的线程挂起;
  • 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题.

4.1 线程不安全举例

举例:不安全的售票

package com.sjmp.Concurrent;/*** @author: sjmp1573* @date: 2020/11/17 22:03* @description:*/public class UnsafeBuyTicket {}class BuyTicket implements Runnable{private int ticketNum = 10;boolean  flag = true;@Overridepublic void run() {while (flag){buy();}System.out.println("售罄");}//加关键字 synchronized 就可以变成线程安全的public void buy(){if (ticketNum<=0){flag = false;return;}try {//            模拟买票延时Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" get ticket:"+ticketNum);ticketNum--;}public static void main(String[] args) {BuyTicket buyTicket = new BuyTicket();Thread thread01 = new Thread(buyTicket,"01");Thread thread02 = new Thread(buyTicket,"02");Thread thread03 = new Thread(buyTicket,"03");thread01.start();thread02.start();thread03.start();}
}

举例:银行取钱
代码省略

举例:线程不安全的集合
可参考:ArrayList为什么是线程不安全的:https://blog.csdn.net/qq_42183409/article/details/100586255

package com.sjmp.Concurrent;import java.util.ArrayList;/*** @author: sjmp1573* @date: 2020/11/17 22:22* @description:*/public class UnsafeList {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();for (int i = 0; i < 10000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}

举例:线程安全的集合:CopyOnWriteArrayList

package com.sjmp.Concurrent;import java.util.concurrent.CopyOnWriteArrayList;/*** @author: sjmp1573* @date: 2020/11/18 9:48* @description:*/public class TestJUC {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();for (int i = 0; i < 1000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}

4.2 同步方法

  • 由于我们可以通过关键字 private 关键字来保证数据对象只能被方法访问,所以我们只要针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种方法:
    synchronized 方法和 synchronized 块.

同步方法:

public synchronized void method(int args){}
  • synchronized 方法控制 “对象” 的访问,每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放,后面被阻塞的线程才能获得这个锁,继续执行。
    缺陷:若将一个大的方法申明为 synchronized 将会影响效率。

在这里插入图片描述

4.3 同步块

同步块:synchronized(Obj){}
Obj 称之为同步监视器

  • Obj 可以是任何对象,但是推荐使用共享资源作为同步监视器
  • 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是 this ,就是这个对象本身,或者是 class
  • 同步监视器的执行过程
  1. 第一个线程访问,锁定同步监视器,执行其中的代码
  2. 第二个线程访问,发现同步监视器被锁定,无法访问
  3. 第一个线程访问完毕,解锁同步监视器
  4. 第二个线程访问,发现同步监视器没有锁,然后锁定并访问

4.3 死锁

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥“两个以上对象的锁”时,就可能会发生“死锁”的问题。

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

上述四个条件,只要破坏其任意一个就可避免死锁的发生。

4.4 Lock(锁)

  • 从 JDK 5.0 开始,Java 提供了更强大的线程同步机制——通过显示定义同步锁对象来实现同步。同步锁使用 Lock对象充当
  • java.util.concurrent.locks.Lock 接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lock 对象
  • ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是 ReentrantLock ,可以显示加锁、释放锁。

synchronized 与 Lock 的对比

  • Lock 是显示锁(手动开启和关闭),synchronized 是隐式锁,出了作用域自动释放
  • Lock 只有代码加锁,synchronized 有代码块锁和方法锁
  • 使用 Lock 锁,JVM 将花费较少的时间来调度线程,性能更好。并具有更好的扩展性(提供更多的子类)
  • Lock > 同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)
package com.sjmp.Concurrent;import java.util.concurrent.locks.ReentrantLock;/*** @author: sjmp1573* @date: 2020/11/18 16:52* @description:*/public class TestLock {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(ticket).start();new Thread(ticket).start();new Thread(ticket).start();}}class Ticket extends Thread{private int ticketNums = 10;
//    定义 lock 锁private final ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while(true){try{lock.lock();if (ticketNums>0){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(ticketNums--);}else{break;}}finally {lock.unlock();}}}
}

5.线程通信

应用场景:生产者和消费者问题

  • 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费。

  • 如果仓库中没有产品,则将生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。

  • 如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费,直到仓库中再次放入产品为止。

在这里插入图片描述

这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。

  • 对于生产者,没有生产产品之前,要通知消费者等待.而生产了产品之后,又需要马上通知消费者消费
  • 对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品以供消费.
  • 在生产者消费者问题中,仅有synchronized是不够的
    synchronized 可阻止并发更新同一个共享资源,实现了同步
    synchronized 不能用来实现不同线程之间的消息传递(通信)

5.1 解决线程之间通信问题的几个方法

注意:均是 Object 类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常 llegalMonitorStateException

在这里插入图片描述
sleep 与 wait 的区别可参考链接:https://www.xuexila.com/baikezhishi/537124.html

5.2 解决线程之间通信的方式1:管程法

并发写作模型“生产者/消费者模式”–>管程法

  • 生产者:负责生产数据的模块(可能是方法,对象,线程,进程);
  • 消费者:负责处理数据的模块(可能是方法,对象,线程,进程)
  • 缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区

生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据

在这里插入图片描述

package com.sjmp.advanced;/*** @author: sjmp1573* @date: 2020/11/18 20:52* @description:*/// 生产者,消费者,产品,缓冲区
public class TestPC {public static void main(String[] args) {SynContainer container = new SynContainer();new Productor(container).start();new Consumer(container).start();}}// 生产者
class Productor extends Thread{SynContainer container;public Productor(SynContainer container){this.container = container;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("生产了"+i+"只鸡");container.push(new Chicken(i));}}
}class SynContainer{
//    需要一个容器的大小Chicken[] chickens = new Chicken[10];
//    容器计数器int count = 0;//    生产者放入产品public synchronized void push(Chicken chicken){
//        如果容器满了,就需要等待消费者消费if (count == chickens.length){
//            通知消费者消费,生产等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}chickens[count] = chicken;count++;this.notifyAll();}//    消费者消费产品public synchronized Chicken pop(){
//        判断能否消费if(count==0){
//            等待生产者生产,消费者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}
//        如果可以消费count--;Chicken chicken = chickens[count];
//        可以通知消费了this.notifyAll();return chicken;}
}class Consumer extends Thread{SynContainer container;public Consumer(SynContainer container){this.container = container;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("消费了-->"+container.pop().id+"只鸡");}}
}// 产品
class Chicken{int id;  //产品编号public Chicken(int id){this.id = id;}
}

5.3 解决线程之间通信的方式1:信号灯法

package com.sjmp.advanced;/*** @author: sjmp1573* @date: 2020/11/18 21:34* @description:*/public class TestPC2 {public static void main(String[] args) {TV tv = new TV();new Player(tv).start();new Wathcher(tv).start();}
}//生产者--演员
class Player extends Thread{TV tv;public Player(TV tv){this.tv = tv;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {if(i%2==0){this.tv.play("快乐大本营");}else{this.tv.play("天天向上");}}}
}//观众
class Wathcher extends Thread{TV tv;public Wathcher(TV tv){this.tv = tv;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {tv.watch();}}
}//产品--节目
class TV{
//    演员表演,观众等待  T
//    观众观看,演员等待  FString voice;  // 表演节目boolean flag = true;//    表演public synchronized void play(String voice){if(!flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("演员表演了: "+voice);
//        通知观众观看this.notifyAll();// 通知唤醒this.voice = voice;this.flag = !flag;}//    观看public synchronized void watch(){if (flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("观看了: "+voice);
//        通知演员表演this.notifyAll();this.flag = !this.flag;}
}

5.4 使用线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。

优点:
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程管理…

  • corePoolSize:核心池的大小
  • maximumPoolSize:最大线程数
  • keepAliveTime:线程没有任务时最多保持多长时间会终止
package com.sjmp.advanced;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author: sjmp1573* @date: 2020/11/18 21:53* @description:*/public class TestPool {public static void main(String[] args) {
//        1.创建服务,创建线程池ExecutorService service = Executors.newFixedThreadPool(10);
//        newFixedThreadPool 参数为线程池大小
//        执行service.execute(new MyThread());service.execute(new MyThread());service.execute(new MyThread());service.execute(new MyThread());//        2.关闭连接service.shutdown();}
}
class MyThread implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}

6 补充内容

package com.sjmp.Thread01;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** @ClassName ThreadFutureTest* @Description TODO* @Author sjmp1573* @Date DATE{TIME}*/
public class ThreadFutureTest {public static class CallerTask implements Callable<String>{@Overridepublic String call() throws Exception {return "Thread-Callable- hello";}}public static void main(String[] args) {// 创建异步任务FutureTask<String> futureTask = new FutureTask<>(new CallerTask());new Thread(futureTask).start();try {String result = futureTask.get();System.out.println(result);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}

如上代码中的 CallerTask 类实现了 Callable 接口的 call() 方法。在 main 函数内首先创建了一个 FutrueTask 对象(构造函数为 CallerTask 的实例),然后使用创建的 FutrueTask 对象作为任务创建了一个线程并且启动它,最后通过futureTask.get() 等待任务执行完毕并返回结果。

小结:使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过 set 方法设置参数或者通过构造函数进行传递,而如果使用 Runnable 方式,则只能使用主线程里面被声明为 final 的变量。不好的地方是 Java 不支持多继承,如果继承了 Thread 类,那么子类不能再继承其他类,而 Runable 则没有这个限制。前两种方式都没办法拿到任务的返回结果,但是 Futuretask 方式可以。

6.1 wait() 方法

虚假唤醒

w​​​​​​​​

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Keil相关部分界面“μVision”显示为“礦ision”的解决方法

    第一步&#xff0c;打开注册表编辑器&#xff0c;按下“WinR”&#xff0c;输入“regedit”&#xff0c;点击“确定”即可打开注册表编辑器&#xff1b; 第二步&#xff0c;在注册表编辑器中点开“HKEY_CLASSES_ROOT”&#xff1b; 第三步&#xff0c;下拉找到“UV2FILE”&…...

    2024/4/27 23:34:15
  2. 【笔记】PP-YOLO、PP-YOLOv2、PP-YOLO Tiny

    &Title PP-YOLO: An Effective and Efficient Implementation of Object Detector&#xff08;2020&#xff09;PP-YOLOv2: A Practical Object Detector&#xff08;2021&#xff09;代码 &Summary 目标检测算法的准确性和推理速度不可兼得&#xff0c;本文的工作旨…...

    2024/4/27 9:08:21
  3. Intel Edge Insights for Autonomous Mobile Robots

    主要是这个方案&#xff0c;他提供了什么样的功能&#xff1f;价格多少钱&#xff1f;性能如何&#xff1f;对此进行了解&#xff0c;然后可以给大家介绍一下 Research Goals 功能价格性能 文章目录EI for AMRHow it WorksModules and ServicesDriversMiddlewareAlgorithmsApp…...

    2024/4/27 22:32:48
  4. FCN网络结构解析

    daily&#xff1a;作为深度学习图片分割第一个学习的网络结构 Q1&#xff1a; 为什么要用FCN&#xff1f; A1&#xff1a;应为和以前网络R-CNN&#xff0c;SDS相比提升比较大 Q2&#xff1a;与CNN什么区别&#xff1f; A2:使用全卷积层代替全连接层 Q3&#xff1a;为什么要进行…...

    2024/4/28 6:41:13
  5. 还剩3个月过年,我能为产品经理求职做点什么?

    还剩3个月过年&#xff0c;我能为产品经理求职做点什么&#xff1f; 转载自&#xff1a;https://zhuanlan.zhihu.com/p/428777821 现在已经进入11月份了&#xff0c;明年过年是在2月1日&#xff0c;留给今年找工作的还有3个月的时间&#xff0c;在这个时间里&#xff0c;我想跟…...

    2024/4/27 0:28:15
  6. 小解:b、B

    b&#xff1a;全称为&#xff1a;bit&#xff0c;中文名“比特”&#xff0c;bit是计算机中的最小数据单位&#xff0c;人们常说的“8比特”&#xff0c;“比特位”中的“比特”&#xff0c;指的就是这个单位 → bit。在计算机中&#xff0c;数据都是由二进制数 0 /1 组成&a…...

    2024/4/27 21:52:05
  7. T31系统Day4-工程规约

    一.作业 二.应用分层 三.Maven Maven排除依赖 四.二方库依赖 什么是二方库 一方库&#xff1a;本工程中的各模块的相互依赖 二方库&#xff1a;公司内部的依赖库&#xff0c;一般指公司 内部的其他项目发布的jar包 三方库&#xff1a;公司之外的开源库 比如apache Goo…...

    2024/4/20 9:28:53
  8. Redis核心技术与实战笔记(1)

    对一个大型软件系统的更好的学习方式&#xff1a;先建立起系统观&#xff0c;再关注具体的细枝末节。 先考虑简单的键值数据库架构&#xff1a; 理解数据模型和操作接口&#xff0c;知道Redis可以做什么&#xff0c;不能做什么。 数据模型&#xff1a; key-value类型&#x…...

    2024/4/28 0:05:11
  9. 21天好习惯第一期--12

    今天我学习了递推法&#xff0c;学习了如何正确地使用for语句&#xff0c;do-while语句和while语句 for&#xff08;表达式1;表达式2;表达式3) ↑ ↑ ↖ 循环初始条件&#xff0c;循环控制条件&#xff0c;循环转化条件 表达式1;循环初始条…...

    2024/4/15 6:02:37
  10. 谈谈GIS三维渲染引擎

    minemap:是我们公司的产品&#xff0c;主要以earth的形态展示&#xff0c;支持矢量切片倾斜数据&#xff08;这一点我个人认为是它最大的优点&#xff0c;即兼容了矢量切片精美地图又兼容倾斜数据&#xff0c;目前倾斜数据采用的3dtile格式&#xff09;&#xff0c;目前正在重构…...

    2024/4/21 0:14:14
  11. 地图数据快速渲染------基于传统GIS平台多服务器切片

    传统的地理信息平台显示矢量数据的方式或栅格数据&#xff0c;是直接渲染在软件上进行展示&#xff0c;需要配以专业的地图软件、符号库、字体库等内容。随着BS端对于地图展示的要求&#xff0c;传统的渲染方式已经不能满足要求&#xff08;需要的前置条件太多&#xff0c;而且…...

    2024/4/25 16:23:51
  12. mysql中isnull,ifnull的用法及区别

    isnull(expr)的用法 如果expr为null&#xff0c;isnull()返回1&#xff0c;否则返回0 mysql> select isnull(11); -> 0 mysql> select isnull(1/0); -> 1 ifnull(expr1, expr2) 的用法 如果expr1为null,则返回expr2,否则返回expr1 mysql> SELECT IFNUL…...

    2024/4/20 7:44:34
  13. 手机号归属地数据库;根据手机号查找对应的归属地;

    我在网上找到了一份手机号对应归属地的数据库文档。 链接: https://pan.baidu.com/s/1MQtDkw3sowNmdSeoVJUbEA 密码: tp1o 链接: https://pan.baidu.com/s/1pzh_FqXOP_6Ta103K5Cmyw 密码: 9j5r 如有需要&#xff0c;先点赞、关注&#xff0c;再下载。...

    2024/4/27 1:32:25
  14. LeetCode 76. 最小覆盖子串

    给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如…...

    2024/4/26 20:14:54
  15. CHAP协议认证模式

    CHAP&#xff1a;挑战握手认证协议 &#xff0c;是 PPP 协议集中的一种链路控制协议&#xff0c;在网络物理连接后进行连接安全性验证的协议。通过三次握手周期性的校验对端的身份&#xff0c;在初始链路建立时完成&#xff0c;可以在链路建立之后的任何时候重复进行&#xff0…...

    2024/4/27 23:05:12
  16. 从SVN服务器下载project到本地

    从SVN服务器下载project到本地&#xff1a; 马克- to-win&#xff1a;马克 java社区&#xff1a;防盗版实名手机尾号&#xff1a; 73203 1.在资源库视图里点击资源库左边的小加号后出现该资源库下的所有project 2.选择要下载的project右击 --> 检出为 看输出窗口&#xff0…...

    2024/4/27 0:55:56
  17. ORACLE —— 事务

    什么是事务&#xff1f; 在数据库中&#xff0c;事务是工作的逻辑单元。一个事务可以是一个SQL语句&#xff0c;也可以是多个完成一系列操作的SQL语句。事务机制是确保这些SQL语句要么全部成功执行&#xff0c;完成整个逻辑单元&#xff0c;要么一条也不执行。 事务特性&…...

    2024/4/27 5:01:41
  18. 17. STM32——SPI硬件

    STM32——SPISPI协议SPI接口SPI接口框图SPI工作原理时钟信号的相位和极性CPHA 0CPHA 1SPI中断状态标志发送缓存器空闲标志&#xff08;TXE&#xff09;接收缓冲器非空(RXNE)忙BUSY标志SPI引脚配置从设备引脚管理(NSS)①软件模式&#xff1a;②硬件模式&#xff1a;SPI结构体S…...

    2024/4/24 19:21:23
  19. PS2022免安装绿色版

    10月&#xff0c;Adobe更新全系产品至2022版&#xff0c;Adobe旗下的产品深入多媒体领域的方方面面&#xff0c;对于大家来说&#xff0c;用的最多的当属Photoshop。 Photoshop的相关资源&#xff0c;目前在国内主要是由vposy封装制作&#xff0c;它的优点显而易见&#xff0c;…...

    2024/4/20 11:16:22
  20. Mysql 常用命令-2021-11-03

    1.mysql (-h localhost -P 3306) -u root -p password :进入mysql 2.net start mysql/net stop mysql:启动或者关闭mysql服务 3.show databases; 显示数据库列表 4.use databaseName; 使用数据库 5.show tables; 显示当前数据库中的表 6.show tables from otherDatabaseName; …...

    2024/4/19 17:30:23

最新文章

  1. sql server 数据库的学习

    前言&#xff1a; SQL Server是由微软公司开发的一种关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;用于存储和检索数据。它提供了一个可扩展的、安全的和可靠的数据存储和管理解决方案&#xff0c;并主要用于构建企业级应用程序。SQL Server支持使用SQL&…...

    2024/4/28 7:43:38
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. uos安装lxml避坑记录

    环境&#xff1a;紫光电脑uos系统 python&#xff1a;系统自带3.7.3 条件&#xff1a;已打开开发者模式&#xff0c;可以自行安装应用商店之外的软件 一、pip3 install lxml4.8.0可以正正常下载&#xff0c;但出现如下错误 另&#xff1a;为什么是4.8.0&#xff1f;因为这个…...

    2024/4/27 8:52:59
  4. 从头开发一个RISC-V的操作系统(二)RISC-V 指令集架构介绍

    文章目录 前提ISA的基本介绍ISA是什么CISC vs RISCISA的宽度 RISC-V指令集RISC-V ISA的命名规范模块化的ISA通用寄存器Hart特权级别内存管理与保护异常和中断 目标&#xff1a;通过这一个系列课程的学习&#xff0c;开发出一个简易的在RISC-V指令集架构上运行的操作系统。 前提…...

    2024/4/24 5:34:22
  5. OpenAI 宣布, ChatGPT 网页端无需注册就能立即使用(2024年4月1日)

    今天&#xff0c;OpenAI宣布&#xff0c;为了让更多人轻松体验人工智能的强大功能&#xff0c;现在无需注册账户即可立即使用 ChatGPT。这一变化是他们使命的核心部分&#xff0c;即让像 ChatGPT 这样的工具广泛可用&#xff0c;让世界各地的人们都能享受到 AI 带来的好处。 网…...

    2024/4/23 17:22:07
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/28 3:28:32
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/28 1:22:35
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57