Java线程概念集合

线程

概念

1.程序:为解决某种问题,使用计算机语言编写的一系列指令(代码)的集合

2.进程:正在运行的程序(被加载到内存中),是操作系统进行资源分配的最小单位

3.线程:进程可以进一步细化为线程(比进程更小)且线程是隶属于进程的,是操作系统执行的最小的执行单元 也是cpu进行任务调度的最小单位

  • 如 :运行的QQ也是一个进程,操作系统就会为这个进程分配资源 一个聊天窗口就是一个线程,线程隶属于进程

tips:早期是没有线程的,是以进程为单位执行的,进程的单位比较大,当一个进程运行时,其他进程就不能执行了,所以后来,将进程中的多个任务细化为线程,cpu的执行单位,也是从进程进化为更小的线程

总结

  1. 一个进程可以包含多个线程
  2. 一个线程只能隶属于一个进程,线程不能脱离进程单独独立运行
  3. 一个进程中至少有一个线程,即主线程,javamian方法就是用来启动主线程
  4. 在主线程中可以创建并启动其他线程,所有线程都共享进程的内存资源
  5. 所有线程都共享进程资源

Thread类

JavaThread表示线程,提供了许多的方法,来对线程的控制,可以通过继承Thread 类来实现线程

Thread常用方法

  • Thread.currentThread();
    • 获取当前运行的线程
  • run();
    • 线程要执行的任务
  • start();
    • 启动Java线程
  • setName(String name);
    • 设置线程名字
  • (String)getName();
    • 获取线程名字
  • getPriority();
    • 获取线程优先级
  • setPriority();
    • 设置线程优先级 1~10一般线程默认优先 5
  • sleep(long ms);
    • 设置线程休眠
  • join();
    • 让其他线程等待这个线程结束后,其他线程再执行

Thread构造方法

  • new Thread(Runnable runnable);
    • 接受一个任务对象
  • new Thread(Runnable runnable,String name);
    • 接受一个对象 并为对象设置名字

使用上面方法进行实例

线程1
public class MyThread extends Thread{

    //重写run方法,在run中执行我们要执行的方法
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            System.out.println("循环main"+i);
        }
    }

}
线程2
public class MyThread2 extends Thread {
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            System.out.println("循环main2"+i);
        }
    }
}
public class 线程 {
    public static void main(String[] args) {
        for(int i=0;i<10000;i++){
            System.out.println("循环1 "+i);
        }
        for(int i=0;i<10000;i++){
            System.out.println("循环2 "+i);
        }
        for(int i=0;i<10000;i++){
            System.out.println("循环3 "+i);
        }
        for(int i=0;i<10000;i++){
            System.out.println("循环4 "+i);
        }
        /*
        这样不管怎么执行都是单线程,从上到下依次执行,

        所以如果想在java程序中有几件不想管的事件同时执行
         可以在java中创建线程,把一些需要执行的任务放在线程中执行,
         这样就拥有让cup执行的权利
         */
        MyThread myThread = new MyThread();
        //调用start方法让程序多线程进行,重写run方法但不能调用run,不然只是普通方法的调用,依然是单线程
        myThread.start();
        MyThread2 myThread2 = new MyThread2();
        myThread2.start();

    }

}

image-20231207203645612

观察结果 可知 MyThreadMyThread2是同时进行的

Runnable接口

Java中我们也可以实现Runnable接口来进行对线程的实现

思路.

  • 创建一个类 实现Runnable接口 重写run方法

  • 在main函数使用Thread构造方法传入Runnable对象

  • public class MyTask implements Runnable{
        @Override
        public void run() {
            for(int i=0;i<10;i++){
                System.out.println("啊");
            }
        }
    }
    
  • MyTask myTask = new MyTask();
           //创建一个线程
           Thread thread = new Thread(myTask);
    

Callable接口

Java中也可以实现Callable接口 重写 call()方法 来对线程的实现

思路.

  • 重写call()方法 call()方法有返回值 可以抛出异常,还可以处理不同类型
  • 依然使用Thread构造方法来创建一个线程

关于线程的其他概念

线程生命周期

从线程到销毁期间经历五个状态

image-20231029190539052

守护线程(也是线程的一种)

  • setDaemon();如果一个线程守护线程,那么它会等待java中其他线程任务结束后,自动终止
  • 守护线程是为其他线程提供服务的,eg:jvm中的垃圾回收机制,就是一个守护线程

多线程

在一个应用程序中,存在多个线程,不同线程可以并行的执行任务

操作系统线程任务调度算法

  1. 先来先服务调度算法
  2. 短作业优先调度算法
  3. 优先级调度算法
  4. 高响应比优先调度算法
  5. 时间片轮转调度算法
  6. 多级反馈队列调度算法(集合前几种算法的优点)

对线程进行加锁

分析

  • 多线程的优点
    • 提高程序的处理能力
    • 提高CPU的 利用率
  • 缺点
    • 线程也是需要占用内存资源和CPU资源
    • 多个线程对同一个共享资源进行访问,会出现线程安全问题

对于内存资源与CPU资源我们可以通过不断增加内存来解决

对于线程安全问题 我们则需要对 线程进行加锁

synchronized

synchronized 修饰代码块需要加一个同步对象 synchronized(同步对象)

同步对象要求

  • 多线程用到的对象必须是同一个对象
  • 可以是java类中任何类对象.
  • 作用:用来记录有没有线程进入到同步代码块中

修饰方法

  • 锁不需要我们提供,会默认提供锁对象
  • synchronized如果修饰的是非静态方法,锁的对象是this
  • 如果是静态方法,锁的对象是Class的对象 (一个类只能有一个对象)

修饰代码块例子

package day17;

public class PrintNums implements Runnable{
    //实现线程的交替打印
    int num=100;
    Object object = new Object();
    @Override
    public void run() {
        while(true){
            synchronized (object){
                object.notify();//唤醒线程
                if(num==0){
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"."+num+".");
                num--;
                try {
                    object.wait();//线程等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package day17;

public class TestPrintNums {
    public static void main(String[] args) {
        PrintNums printNums = new PrintNums();
        Thread t1 = new Thread(printNums,"1");
        Thread t2 = new Thread(printNums,"2");
        Thread t3 = new Thread(printNums,"3");
        t1.start();
        t2.start();
        t3.start();
    }
}

image-20231207211850022

于是我们实现了交替打印 每次只能进入一个线程

修饰方法(同步对象会有默认的)

  1. 锁不需要我们提供,会默认提供对象锁
  2. synchronized如果修饰的是非静态方法,锁的对象是this

synchronized如果修饰的是静态方法,锁的对象是类的Class对象,一个类只有 一个对象

  • 如果是非静态方法,那么同步对象是this(如果是非静态对象,我们可以使用Runnable创建线程方法)

  • 如果是静态方法,所得对象是当前类的Class对象

  • 当前类的Class对象:一个类加载到内存后会为这个类创建唯一的Class类的对象

  • Class类实例表示正在运行的Java应用程序中的类和接口

  • 修饰静态方法
    public class SellTicket extends Thread {
        static int counts = 10;//10张票
        static Object object = new Object();
    
        @Override
        public void run() {
    
            while (counts > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sellTicket();
            }
        }
    
        public static synchronized void sellTicket() {
            if(counts>0){
                System.out.println(Thread.currentThread().getName()+"买了"+counts+"张票");
                --counts;
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            SellTicket t1 = new SellTicket();
            t1.setName("窗口1");
            SellTicket t2 = new SellTicket();
            t2.setName("窗口2");
    
            t1.start();
            t2.start();
        }
    }
    

    image-20231209231353289

  • 修饰非静态方法
    public class SellTickets2 implements Runnable{
    
        int t=20;//票数
    
        @Override
        public void run() {
            while(t>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sell2();
            }
        }
        public synchronized void sell2(){
            if(t>0){
                System.out.println(Thread.currentThread().getName()+"买了"+t+"张票");
                --t;
            }
        }
    }
    
    public class Test2 {
        public static void main(String[] args) {
            SellTickets2 sellTickets2 = new SellTickets2();
            Thread t1 = new Thread(sellTickets2,"窗口1");
            Thread t2 = new Thread(sellTickets2,"窗口2");
    
            t1.start();
            t2.start();
        }
    }
    

    image-20231209231446179

ReentrantLock类加锁

  • 只能对某一代码块进行加锁,不能对整个方法加锁
  • 加锁方法如下
ReentrantLock r = new ReentrantLock();//创建 ReentrantLock对象
r.lock();<---------|//加锁
                   |
  .............    |------被锁部分(一次只进去一个线程)
                   |
r.unlock();<-------|//解锁

tips:r.unlock();最好写在finally{};代码块中,保证发生异常时,也能够解锁;

synchronized与ReentrantLock的区别

  1. synchronized是一个关键字,ReentrantLock是一个类

  2. synchronized修饰代码块和方法,ReentrantLock只能修饰代码块

  3. synchronized可以隐式的加锁和释放锁,运行出现异常可以自动释放锁

    ReentrantLock需要手动加锁和释放锁,建议在finally代码中释放锁

常用的三个方法 wait notify notifyAll

  • wait();方法使当前线程进入等待状态,直到另一个线程调用该对象的notify()notifyAll()方法来唤醒它

  • notify();方法唤醒在该对象上调用wait()方法进入等待状态的一个线程,如果有多个线程在等待,则只会唤醒其中一个线程。

  • notifyAll();方法唤醒在该对象上调用wait()方法进入等待状态的所有线程。

    tips:1.都是Object类中定义的方法

    ​ 2.三个方法必须在同步代码块中使用

    ​ 3.这三个方法必须通过为锁的对象调用

posted @   Yang0710  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
  1. 1 イエスタデイ(翻自 Official髭男dism) 茶泡饭,春茶,kobasolo
  2. 2 世间美好与你环环相扣 柏松
世间美好与你环环相扣 - 柏松
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 尹初七

作曲 : 柏松

编曲 : 彭圣杰

偏偏秉烛夜游

偏偏秉烛夜游

午夜星辰 似奔走之友

爱你每个结痂伤口

酿成的陈年烈酒

入喉尚算可口

入喉尚算可口

怎么泪水 还偶尔失守

邀你细看心中缺口

裂缝中留存 温柔

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

让樱花偷偷 吻你额头

让世间美好 与你环环相扣

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

当樱花开的纷纷扬扬

当世间美好 与你环环相扣

特别鸣谢:槿葵,我们的海报制作妹妹。

原唱:柏松

吉他:柏松

和声:柏松

录音:柏松

混音:张强

点击右上角即可分享
微信分享提示