欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > 01、多线程高并发基础

01、多线程高并发基础

2025/6/24 4:57:56 来源:https://blog.csdn.net/qq_21451945/article/details/144628703  浏览:    关键词:01、多线程高并发基础

本篇文章主要讲一些和线程,进程,的基础常识问题

1、进程和线程的基本概念

  • 进程:一个程序启动(或是一个应用启动)就是一个程序,它是资源分配的基本单元,相当于是一个装很多线程的容器
  • 线程:线程是CPU调度的基本单位,每个线程都会执行进程的一些代码片段
  • 串行,并行,并发
    • 串行:多个线程排队,一个一个的上
    • 并行:多个线程一起上,这里必须是多个CPU或是大CPU多个核的情况下,才能实现并行
    • 并发:区别于高并发(1w个请求同时访问这个接口)里的定义,这里的并发是指CPU在极短的时间内对不同的线程进行切换,来达到多个线程同时运行这样的效果。单核但CPU也可以并发但是不能并行。
  • 同步,异步,阻塞,非阻塞
    • 同步,异步:在调用一个功能时,看它是否会主动给调用者反馈信息,会主动反馈的就是异步,反之就是同步
    • 阻塞,非阻塞:在调用一个功能时,此时调用者还能不能同时去干其他事情,如果可以,那就是非阻塞,反正就是阻塞

2、创建线程的方式

从本质上说,创建线程的方式只有一种,那就是创建一个线程对象,然后调用start方法。

  • 从大的方面来说,创建线程的方法有三种
    • 继承Tread类,重新run方法
    public class MiTest {public static void main(String[] args) {MyJob t1 = new MyJob();t1.start();for (int i = 0; i < 100; i++) {System.out.println("main:" + i);}}}
    class MyJob extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("MyJob:" + i);}}
    }
    
    • 实现Runable接口,重写run方法
    public class MiTest {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t1 = new Thread(myRunnable);t1.start();for (int i = 0; i < 1000; i++) {System.out.println("main:" + i);}}}
    class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println("MyRunnable:" + i);}}
    }
    

    它对应的还有两种常见的实现方式
    1. 匿名内部类
    2. lambad方式

    // 匿名内部类方式
    Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println("匿名内部类:" + i);}}
    });
    
    // lambad表达式的方式
    Thread t2 = new Thread(() -> {for (int i = 0; i < 100; i++) {System.out.println("lambda:" + i);}
    });
    
    • 实现Callable接口,重写call方法

    Callable它的call方法可以带结果返回,而且他是一种非阻塞的同步方法

    public class MiTest {public static void main(String[] args) throws ExecutionException, InterruptedException {//1. 创建MyCallableMyCallable myCallable = new MyCallable();//2. 创建FutureTask,传入CallableFutureTask futureTask = new FutureTask(myCallable);//3. 创建Thread线程Thread t1 = new Thread(futureTask);//4. 启动线程t1.start();//5. 做一些操作//6. 要结果Object count = futureTask.get();System.out.println("总和为:" + count);}
    }class MyCallable implements Callable{@Overridepublic Object call() throws Exception {int count = 0;for (int i = 0; i < 100; i++) {count += i;}return count;}
    }
    

3、线程的使用方式

3.1、线程的状态

  • new:Thread对象被创建出来,但是还没有执行start方法
  • runnnable:对象调用了start方法,正常运行对应的代码
  • blocked:被阻塞,如在多线程加锁的情况下,对应的线程没有拿到锁,就会处于blocked状态
  • waiting:调用wait方法,这种需要手动唤醒
  • time_waiting:调用sleep或是join方法,到了时间或是特定的条件达成就会唤醒,继续跑
  • terminated:run方法执行完之后,线程对应的状态

3.2、现成常用的方法

  • 获取当前线程:Thread.currentThread()
public static void main(String[] args) throws ExecutionException, InterruptedException {// 获取当前线程的方法Thread main = Thread.currentThread();System.out.println(main);// "Thread[" + getName() + "," + getPriority() + "," +  group.getName() + "]";// Thread[main,5,main]
}
  • 线程的名称:thread.getName()
public static void main(String[] args) throws ExecutionException, InterruptedException {Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName());});t1.setName("模块-功能-计数器");t1.start();
}
  • 线程的优先级:thread.setPriority(1)

其实它就是CPU调度线程的优先级,Java中给线程设置了1~10的优先级别

public static void main(String[] args) throws ExecutionException, InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {System.out.println("t1:" + i);}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {System.out.println("t2:" + i);}});t1.setPriority(1);t2.setPriority(10);t2.start();t1.start();
}
  • 线程的让步:Thread.yield()

通过Thread的静态方法yield调用,让当前线程从运行状态转变为就绪状态

public static void main(String[] args) throws ExecutionException, InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 100; i++) {if(i == 50){Thread.yield();}System.out.println("t1:" + i);}});Thread t2 = new Thread(() -> {for (int i = 0; i < 100; i++) {System.out.println("t2:" + i);}});t2.start();t1.start();
}
  • 线程的休眠:Thread.sleep()

让线程从运行状态变为等待状态,sleep方法会抛出一个InterruptedException

public static void main(String[] args) throws InterruptedException {System.out.println(System.currentTimeMillis());Thread.sleep(1000);System.out.println(System.currentTimeMillis());
}
  • 线程的强占:thread.join()

假如在t1中运行t2.jooin(),t1会进入等待状态,一直等到t2运行完毕之后,t1才会进入就绪状态等待CPU运行,如果是t2.join(2000),t1会等t2运行2s之后再开始运行,如果在这2s之内,t2先运行完了,t1也会提前开始运行

public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println("t1:" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();for (int i = 0; i < 10; i++) {System.out.println("main:" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (i == 1){try {t1.join(2000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
  • 守护线程
  • 现成的等待和唤醒
    • wait, notify() , notifyAll()
    public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {sync();},"t1");Thread t2 = new Thread(() -> {sync();},"t2");t1.start();t2.start();Thread.sleep(12000);synchronized (MiTest.class) {MiTest.class.notifyAll();}
    }public static synchronized void sync()  {try {for (int i = 0; i < 10; i++) {if(i == 5) {MiTest.class.wait();}Thread.sleep(1000);System.out.println(Thread.currentThread().getName());}} catch (InterruptedException e) {e.printStackTrace();}
    }
    

3.3、线程的结束方式

让线程停止的方法很多,比如:调用stop(),通过共享变量来破坏死循环来让线程运行结束停止掉,通过interrupt()
其中通过interrupt(),通过打断线程的方式结束时最常见的,也是比较优雅的一种方式

public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(true){// 获取任务// 拿到任务,执行任务// 没有任务了,让线程休眠try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();System.out.println("基于打断形式结束当前线程");return;}}});t1.start();Thread.sleep(500);//把t1停止掉,此时会进行t1.interrupt();
}

3.3、wait和sleep的区别

  • sleep属于Thread类的Static方法,wait是Object类的方法
  • sleep属于Timed_waiting,它根据设置自动唤醒,wait属于Waiting,需要手动唤醒
  • sleep方法在持有锁时,是不会释放锁资源的,wait在执行之后,会释放锁资源
  • sleep方法在有无锁的情况下都可以执行,但是wait方法只有在有锁的时候运行
    • wait方法会将持有锁的线程从owner扔到waitSet中,这个操作是在修改ObjectMonitor对象,如果没有持有synchronized锁的话,是无法操作ObjectMonitor独享的

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词