Java线程

简介: 一、创建线程的两种方式1. 继承Thread类 类1) 定义子类继承Thread类。 2) 子类中重写Thread类中的run方法。 3) 创建Thread子类对象,即创建了线程对象。

一、创建线程的两种方式

1. 继承Thread类 类

1) 定义子类继承Thread类。
2) 子类中重写Thread类中的run方法。
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法。

2. 实现Runnable 接口

1)定义子类,实现Runnable接口。
2)子类中重写Runnable接口中的run方法。
3)通过Thread类含参构造器创建线程对象。
4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法中。
5)调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。

二、Thread 类的有关方法

1)void start(): 启动线程,并执行对象的run()方法。
2)run(): 线程在被调度时执行的操作。
3)String getName(): 返回线程的名称。
4)void setName(String name):设置该线程名称。
5)static currentThread(): 返回当前线程。
6)static void yield(): : 线程让步

  • 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程。
  • 若队列中没有同优先级的线程,忽略此方法。

7)join() : : 当某个程序执行流中调用其他线程的 join() 方法时,调用
线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止。

  • 低优先级的线程也可以获得执行。

8)static void sleep(long millis) :(指定时间:毫秒)

  • 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。

  • 抛出InterruptedException异常。

9)stop(): 强制线程生命期结束。
10)boolean isAlive(): : 返回boolean,判断线程是否还活着。

三、线程的分类

Java中的线程分为两类:一种是 守护线程,一种是 用户线程。

  • 它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
  • 守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
  • Java垃圾回收就是一个典型的守护线程。
  • 若JVM中都是守护线程,当前JVM将退出。

四、线程的生命周期

要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的 五种状态:

1、新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象
处于新建状态。
2、就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,
此时它已具备了运行的条件。
3、运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run()
方法定义了线程的操作和功能。
4、阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU
并临时中止自己的执行,进入阻塞状态。
5、死亡:线程完成了它的全部工作或线程被提前强制性地中止。

五、多线程的安全问题

  1. 多线程出现了安全问题
  2. 问题的原因: 问题的原因:
    当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
  3. 解决办法:
    对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。

六、锁

1、Synchronized 的使用方法

Java对于多线程的安全问题提供了专业的解决方式: 对于多线程的安全问题提供了专业的解决方式:

同步代码块

  • synchronized ( 对象){
    // 需要被同步的代码;
    }
    synchronized 锁的对象可以是this线程本身,也可以是其他对象。

  • synchronized 还可以放在方法声明中,表示整个方法为同步方法。例如:

public synchronized void show (String name){
    …//方法体
}

2、互斥锁

在Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。

  • 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
  • 关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
  • 同步的局限性:导致程序的执行效率要降低。
  • 同步方法(非静态的)的锁为this。
  • 同步方法(静态的)的锁为当前类本身。
    单例模式就是很好的例子:
class Singleton {
    private static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance == null){
                    instance=new Singleton();
                } 
            } 
        }
        return instance;
    }  
}
class TestSingleton{
    public static void main(String[] args){
        Singleton s1=Singleton.getInstance();
        Singleton s2=Singleton.getInstance();
        System.out.println(s1==s2);
    } 
}

3、释放锁的操作

  • 当前线程的同步方法、同步代码块执行结束。
  • 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。
  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

4、不会释放锁的操作

  • 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行。
  • 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。
    注意:应尽量避免使用suspend()和resume()来控制线程。

5、线程的死锁问题

1、 死锁

  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

2、 解决方法

  • 专门的算法、原则
  • 尽量减少同步资源的定义

七、线程通信

wait() 与 notify() 和 notifyAll()

  • wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问。
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
  • notifyAll ():唤醒正在排队等待资源的所有线程结束等待。
  • 注意:Java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.IllegalMonitorStateException异常。并且当前线程必须具有对该对象的监控权(加锁)。

1、wait()方法

  • 在当前线程中调用方法: 对象名.wait()。
  • 使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify (或notifyAll) 为止。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)。
  • 调用此方法后,当前线程将释放对象监控权 ,然后进入等待
  • 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。

2、notify()/notifyAll()

  • 在当前线程中调用方法: 对象名.notify()。
  • 功能:唤醒等待该对象监控权的一个线程。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)。
目录
相关文章
|
1天前
|
Java
死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`
【6月更文挑战第20天】死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`volatile`保证变量的可见性和部分原子性,确保多线程环境中值的即时更新。与`synchronized`相比,`volatile`作用于单个变量,不保证原子操作,同步范围有限,但开销较小。`synchronized`提供更全面的内存语义,保证原子性和可见性,适用于复杂并发控制。
11 3
|
1天前
|
Java
【技术瑜伽师】Java 线程:修炼生命周期的平衡之道,达到多线程编程的最高境界!
【6月更文挑战第19天】Java多线程编程犹如瑜伽修行,从创建线程开始,如`new Thread(Runnable)`,到启动线程的活跃,用`start()`赋予生命。面对竞争与冲突,借助同步机制保证资源访问的有序,如`synchronized`关键字。线程可能阻塞等待,如同瑜伽的静止与耐心。完成任务后线程终止,整个过程需密切关注状态变换,以求多线程间的和谐与平衡。持续修炼,如同瑜伽般持之以恒,实现高效稳定的多线程程序。
|
1天前
|
Java
【代码诗人】Java线程的生与死:一首关于生命周期的赞歌!
【6月更文挑战第19天】Java线程生命周期,如诗般描绘了从新建到死亡的旅程:创建后待命,`start()`使其就绪,获得CPU则运行,等待资源则阻塞,任务完或中断即死亡。理解生命周期,善用锁、线程池,优雅处理异常,确保程序高效稳定。线程管理,既是艺术,也是技术。
|
1天前
|
安全 Java
【极客档案】Java 线程:解锁生命周期的秘密,成为多线程世界的主宰者!
【6月更文挑战第19天】Java多线程编程中,掌握线程生命周期是关键。创建线程可通过继承`Thread`或实现`Runnable`,调用`start()`使线程进入就绪状态。利用`synchronized`保证线程安全,处理阻塞状态,注意资源管理,如使用线程池优化。通过实践与总结,成为多线程编程的专家。
|
1天前
|
Java 开发者
JAVA多线程初学者必看:为何选择继承Thread还是Runnable,这其中有何玄机?
【6月更文挑战第19天】在Java中创建线程,可选择继承Thread类或实现Runnable接口。继承Thread直接运行,但限制了多重继承;实现Runnable更灵活,允许多线程共享资源且利于代码组织。推荐实现Runnable接口,以保持类的继承灵活性和更好的资源管理。
|
1天前
|
Java 开发者
告别单线程时代!Java 多线程入门:选继承 Thread 还是 Runnable?
【6月更文挑战第19天】在Java中,面对多任务需求时,开发者可以选择继承`Thread`或实现`Runnable`接口来创建线程。`Thread`继承直接但限制了单继承,而`Runnable`接口提供多实现的灵活性和资源共享。多线程能提升CPU利用率,适用于并发处理和提高响应速度,如在网络服务器中并发处理请求,增强程序性能。不论是选择哪种方式,都是迈向高效编程的重要一步。
|
1天前
|
Java 开发者
震惊!Java多线程的惊天秘密:你真的会创建线程吗?
【6月更文挑战第19天】Java多线程创建有两种主要方式:继承Thread类和实现Runnable接口。继承Thread限制了多重继承,适合简单场景;实现Runnable接口更灵活,可与其它继承结合,是更常见选择。了解其差异对于高效、健壮的多线程编程至关重要。
|
1天前
|
Java 开发者
【技术成长日记】Java 线程的自我修养:从新手到大师的生命周期修炼手册!
【6月更文挑战第19天】Java线程之旅,从新手到大师的进阶之路:始于创建线程的懵懂,理解就绪与运行状态的成长,克服同步难题的进阶,至洞悉生命周期的精通。通过实例,展示线程的创建、运行与同步,展现技能的不断提升与升华。
|
1天前
|
Java
【代码诗人】Java线程的生与死:一首关于生命周期的赞歌!
【6月更文挑战第19天】在Java中,线程经历新建、就绪、运行、阻塞和死亡5个阶段。通过`start()`从新建转为就绪,进而可能运行;阻塞可能因等待资源;完成任务或中断后死亡。管理线程生命周期涉及合理使用锁、线程池、异常处理和优雅关闭,如使用`volatile`和中断标志。了解这些,能提升程序效率和稳定性。
|
1天前
|
Java
JAVA多线程深度解析:线程的创建之路,你准备好了吗?
【6月更文挑战第19天】Java多线程编程提升效率,通过继承Thread或实现Runnable接口创建线程。Thread类直接继承启动简单,但限制多继承;Runnable接口实现更灵活,允许类继承其他类。示例代码展示了两种创建线程的方法。面对挑战,掌握多线程,让程序高效运行。