JAVA-多线程知识点总结(二)

简介: JAVA-多线程知识点总结(二)

三、多线程的生命周期

3.1JDK5.0之前:五种状态

3.1JDK5.0之后:六种状态

四、线程安全问题及解决

1.概念

线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

2.出现的原因
-- 抢占式执行——罪魁祸首

CPU的调度方法为抢占式执行,随机调度,这个是导致线程安全问题的最根本的原因。但是这个原因我们无能为力,无法改变。

--多个线程同时修改同一个变量

当修改变量这个操作并非原子性的。这样在并发的环境下就很容易出现线程安全问题。这种情况可以通过代码结构来进行一定的规避,但是这种方法不是一个普适性特别高的方案。


--原子性

如果修改操作是原子性的,那么出现线程安全问题的概率还是比较低的。但如果是非原子的(++操作,其可以被拆分为load,add,save三个操作),那么出现问题的概率就非常高了。能够把修改行为变成原子操作,就是解决线程安全问题的关键方法!(synchronized关键字)

--内存可见性问题

内存可见性是指当一个线程修改了共享变量的值,其他线程能够立即感知这个修改。


如果一个线程读,一个线程改(这样的操作就可能引起内存可见性问题,也会出现线程安全问题)。此时前一个线程读取到的值,不一定是修改之后的值,即读线程没有感知到变量的变化——归根结底是编译器/JVM在多线程环境下优化时产生了误判。(volatile关键字)

--指令重排序

指令重排序是因为编译器对我们的代码进行了一些“自作主张”的优化,编译器会在保持逻辑不变的情况下。调整代码的顺序,从而加快代码的执行效率。这样也会出现线程安全问题。

4.线程的同步机制

synchronized解决了线程安全的问题,但在数据共享时多线程是串行执行,性能低。

synchronized 的使用方法:

1.修饰方法

1)修饰普通方法

锁对象是this,谁调用这个普通方法,锁的对象就是谁

2).修饰类方法

锁对象是类对象

2.修饰代码块

显式/手动指定锁对象.

3.可重入

一个线程针对同一个对象加锁两次,是否会有问题,如果没有问题,就叫可重入,如果有问题,就叫不可重入.

a.同步代码块

说明:

--需要被同步的代码,即为操作共享数据的代码。

--共享数据,即多个线程都需要操作的数据。

--需要被同步的代码,在被synchronized包裹以后,就使得一个线程在操作这些代码过程中,其他线程必须等待。


--同步监视器,俗称锁,哪个线程获取了锁,哪个线程就能执行需要被同步的代码


--同步监视器,可以使用任何一个类的对象充当。但是,多个线程必须共同用一个同步监视器。


注意: 在继承Thread类的方式中,同步监视器要慎用this,可以考虑使用:当前类.class。

        在实现Runnable接口的方式中,同步监视器可以考虑使用:this

//用Thread类
class Window extends Thread{
    private static int ticket=100;
   // private static Object object=new Object();
    @Override
    public void run() {
        while(true) {
       // synchronized (object){  
            synchronized (Window.class) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + 
                             ":售票,票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}
public class synchronizedThread {
    public static void main(String[] args) {
        Window w1 = new Window();
        Window w2 = new Window();
        Window w3 = new Window();
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        w1.start();
        w2.start();
        w3.start();
    }
}
 
//用Runnable接口
class Window2 implements Runnable{
    private Integer ticket=100;
    @Override
    public void run() {
        while(true) {
            synchronized (this) {
 
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() +
                              ":售票,票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}
public class synchronizedRunnable {
    public static void main(String[] args) {
        Window2 w = new Window2();
        new Thread(w,"窗口1").start();
        new Thread(w,"窗口2").start();
        new Thread(w,"窗口3").start();
    }
}
b.同步方法

说明:

--如果操作共享数据的代码完整的声明在了一个方法中,就称此方法为同步方法。

--非静态的同步方法,默认同步监视器是this

  静态的同步方法,默认同步监视器是当前类的本身。

(本文图片及内容来自尚硅谷视频,部分补充内容来自:原文链接

//用Runnable接口
class method2 implements Runnable{
    private Integer ticket=100;
    @Override
    public void run() {
        while(true){
            buy();
        }
    }
    public synchronized void buy(){  // 同步监视器为this  ,而且方法也不是static的
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + 
       ":售票,票号为:" + ticket);
            ticket--;
        }
    }
}
public class synchronizedRunnableMethod {
    public static void main(String[] args) {
        method2 m = new method2();
        new Thread(m,"窗口1").start();
        new Thread(m,"窗口2").start();
        new Thread(m,"窗口3").start();
    }
}
 
//用Thread类
class method extends Thread{
    private static Integer ticket=100;
    @Override
    public void run() {
        while(true){
            buy();
        }
    }
 
    // 因为是继承Thread,创建多个线程会创建method类的多个实例,必须声明为static
    public synchronized static void buy(){ // 同步监视器还是类对象本身  method.class
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ":售票,票号为:" + ticket);
            ticket--;
        }
    }
}
public class synchronizedThreadMethod {
    public static void main(String[] args) {
        method m1 = new method();
        method m2 = new method();
        method m3 = new method();
        m1.setName("窗口1");
        m2.setName("窗口2");
        m3.setName("窗口3");
        m1.start();
        m2.start();
        m3.start();
    }
}
 
相关文章
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
184 1
|
2月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
206 1
|
3月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
161 0
|
3月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
259 16
|
4月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
4月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
5月前
|
存储 缓存 安全
Java基础 - 知识点
Java基础知识点涵盖语言特性、面向对象与基本数据类型、缓存池机制、String类特性、参数传递、类型转换、继承、抽象类与接口区别、重写与重载、Object通用方法及关键字使用等核心内容,是掌握Java编程的重要基石。
104 0
|
5月前
|
Java 数据库连接 数据库
Java 相关知识点总结含基础语法进阶技巧及面试重点知识
本文全面总结了Java核心知识点,涵盖基础语法、面向对象、集合框架、并发编程、网络编程及主流框架如Spring生态、MyBatis等,结合JVM原理与性能优化技巧,并通过一个学生信息管理系统的实战案例,帮助你快速掌握Java开发技能,适合Java学习与面试准备。
253 2
Java 相关知识点总结含基础语法进阶技巧及面试重点知识

热门文章

最新文章