Java并发之线程入门一

简介: Java并发之线程入门一、什么是线程?二、线程状态2.1、创建新的线程2.1.1继承Thread类创建线程2.1.1实现Runnable接口创建线程2.2可运行的线程2.3等待线程2.4被终止的线程三、中断线程四、线程属性4.1线程优先级4.2守护线程练习

一、什么是线程?


线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。


线程是独立调度和分派的基本单位.线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。


一个进程可以有很多线程,每条线程并行执行不同的任务。


在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。


二、线程状态


线程有6种状态


1.New(新创建)


2.Runnable(可运行)


3.Blocked(被阻塞)


4.Waiting(等待)


5.Timed wating(计时等待)


6.Terminated(被终止)


要确定一个线程状态。可以调用getState方法


2.1、创建新的线程


常用的创建方式:


1)继承Thread类创建线程


2)实现Runnable接口创建线程


继承关系:

c7490581d2fe4c45ac52a2a2e77bb163.png

2.1.1继承Thread类创建线程


第一步:创建一个类T 使它继承Thread


class T extends Thread{}


第二步骤:重写run方法


@Override public void run(){这里写自己的逻辑方法}


第三步:创建Cat的实例,然后启动线程,即调用线程的start方法


T t = new T(); t.start();


调用start();就会创建一个新的线程,它会执行刚刚重写的run方!!!


代码实列:

package com.final_.thread01;
/**
 * @autor 笑霸fianl~
 * 欢迎访问GitHub:https://github.com/XBfinal
 * 欢迎访问Gitee:https://gitee.com/XBfianl
 * 欢迎访问CSDN:https://blog.csdn.net/weixin_52062043
 * 演示通过继承Thread类创建线程
 */
public class Thread01 {
    //创建一个CAT对象
    public static void main(String[] args) {
        Cat cat = new Cat();
        /******************************/
        cat.start();
        //start就是启动了一个新的线程,程序不会阻塞在这里,还会继续执行main线程
        System.out.println("主线程不会阻塞 继续执行"+  Thread.currentThread().getName());
        for(int i=0;i<100;++i){
            System.out.println(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//1.该类继承了Thread 该类就可以当成线程使用
//2.重写run,添加自己的业务逻辑
class Cat extends Thread{
    @Override
    public void run() {//重写run,添加自己的业务逻辑
        //每个1秒 输出喵喵
       while(true){
           System.out.println("喵喵");
           //让线程休眠1秒
           try {
               Thread.sleep(500);//抛出异常快捷键 ctrl+alt+t
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}
/*****************************************************/
//假如Cat已经继承了其他类 我要实现多线程怎么办?


4e21cafb67c24b3296f36b84e48f4be8.png


以上代码可以看出 有两个线程,每一个线程都在执行循环,所以这个程序在同时执行两个线程(现在在宏观上这么理解,后面有机会讲并发和并行)


注意不能直接调用run方法。如果直接调用他不会创建一个新的线程。


问题😕/假如Cat已经继承了其他类 我要实现多线程怎么办?


所以还能实现Runnable接口方式创建多线程。


2.1.2实现Runnable接口创建线程


1.定义一个类实现Runnable接口,一样要重写run()方法,这个run()方法和Thread中的run()方法一样.


class Dog implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("小狗汪汪叫");
            //休眠1秒
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


2.创建实例,并运行


注意这里不能直接调用start方法,接口没有start方法,但是也不不能直接调用run方法


所以可以间接调用下列代码:


public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        //dog.start
        //不行了,接口没有start方法,但是也不不能直接调用run方法
        //所以可以把dog放入Thread中
        Thread thread = new Thread(dog);//这里使用了静态代理模式
        thread.start();
    }
}


66b3d8e549fd4e2b9a9f98e4e0d3180a.png

66b3d8e549fd4e2b9a9f98e4e0d3180a.png2.2可运行的线程

一旦调用star方法,该线程就处于Runnable(可运行)状态,一个可运行线程是否运行要看系统提供运行的时间


记住在给定时间内,可运行线程可能运行,也可能没有运行(所以这叫可运行线程,不见运行线程)


2.3等待线程


调用Thread.sleep();可以让线程等待单位是毫秒


注意此处有异常抛出


  try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


当然也可以thows。


2.4被终止的线程


原因1.run方法自然死亡或者正常退出


原因2.没有捕获异常终止了run方法而意外死亡


相关的方法


void join()//等待终止线程
void join(long millis)//等待终止线程或者经过指定的毫秒数


三、中断线程


中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。 线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序。 虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果。


void interrrupt())//向线程发送中断请求。线程的中断状态将会被设置为true


package com.final_.thread01;
/**
 * @autor 笑霸fianl~
 * 欢迎访问GitHub:https://github.com/XBfinal
 * 欢迎访问Gitee:https://gitee.com/XBfianl
 * 欢迎访问CSDN:https://blog.csdn.net/weixin_52062043
 */
public class T03 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(1); // 暂停1毫秒
        t.interrupt(); // 中断t线程
        t.join(); // 等待t线程结束
        System.out.println("end");
    }
}
class MyThread extends Thread {
    public void run() {
        int n = 0;
        while (! isInterrupted()) {
            n ++;
            System.out.println(n + " hello!");
        }
    }
}

66b3d8e549fd4e2b9a9f98e4e0d3180a.png

四、线程属性


4.1线程优先级


如果有几个高优先级的线程没有进入非活动状态,低优先级的线程可能永远不会执行,尽管会让低优先级的线程饿死,系统也会在高优先级的线程中选择。


55d4535b1a2f4080b1f4e4deef71738c.png


代码:


public static void main(String[] args) {
    System.out.println(Thread.currentThread().getPriority());
}


4.2守护线程


线程可以是守护线程或用户线程。


唯一的作用守护线程是服务提供者线程。


我们可以通过使用setDaemon()方法通过传递true作为参数,使线程成为一个守护线程


守护线程应该永远不去访问固有资源,因为它会在任何的时候甚至在一个操作的中间发生中断


源代码:


//这一个方法必须在线程启动之前调用
  public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

练习


主线程每隔1秒输出 i你好 一共10次


当主线程输出到 i=5时,启动一个子线程(用Runnable)实现,每隔1秒输出我来了j,j=10,退出 主线程继续输出


代码:


package com.fianl_.ThreadMethod;
/**
 * @autor 笑霸fianl~
 * 欢迎访问GitHub:https://github.com/XBfinal
 * 欢迎访问Gitee:https://gitee.com/XBfianl
 * 欢迎访问CSDN:https://blog.csdn.net/weixin_52062043
 */
/**
 * 主线程每隔1秒输出  i你好 一共10次
 * 当主线程输出到 i=5时,启动一个子线程(用Runnable)实现,每隔1秒输出 我来了j,j=10,退出
 * 主线程继续输出
 *
 * */
public class exercise {
    public static void main(String[] args) throws InterruptedException {
        T1 t1 = new T1();
        for(int i=1;i<=10;i++){
            System.out.println(i+"你好");
            Thread.sleep(1000);
            if(i==5){
                //记住不能直接用t1.start();
                Thread thread = new Thread(t1);
                thread.start();
                thread.join();
            }
        }
    }
}
class T1 implements Runnable{
    @Override
    public void run() {
        for(int j=1;j<=10;j++){
            System.out.println("我来了"+j);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                }
            if(j==10){
                    System.out.println("子线程退出了");
            }
        }
    }
}


c2b935ea5b5145a7a96eeda208fb9b34.png

目录
相关文章
|
7天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
27 9
|
10天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
7天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
10天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
24 3
|
9天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
10天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
21 1
|
6月前
|
数据可视化 Java 测试技术
Java 编程问题:十一、并发-深入探索1
Java 编程问题:十一、并发-深入探索
75 0
|
3月前
|
安全 Java 调度
解锁Java并发编程高阶技能:深入剖析无锁CAS机制、揭秘魔法类Unsafe、精通原子包Atomic,打造高效并发应用
【8月更文挑战第4天】在Java并发编程中,无锁编程以高性能和低延迟应对高并发挑战。核心在于无锁CAS(Compare-And-Swap)机制,它基于硬件支持,确保原子性更新;Unsafe类提供底层内存操作,实现CAS;原子包java.util.concurrent.atomic封装了CAS操作,简化并发编程。通过`AtomicInteger`示例,展现了线程安全的自增操作,突显了这些技术在构建高效并发程序中的关键作用。
69 1
|
14天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
2月前
|
Java API 容器
JAVA并发编程系列(10)Condition条件队列-并发协作者
本文通过一线大厂面试真题,模拟消费者-生产者的场景,通过简洁的代码演示,帮助读者快速理解并复用。文章还详细解释了Condition与Object.wait()、notify()的区别,并探讨了Condition的核心原理及其实现机制。