栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

二、Java内存模型

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二、Java内存模型

.

前言一、线程安全问题二、内置锁(synchronized)

1、非静态同步方法2、同步代码块3、静态同步方法 三、多线程死锁四、Threadlocal

1、什么是Threadlocal2、Threadlocal使用 五、多线程有三大特性

1、原子性2、可见性3、有序性 六、Java内存模型

1、什么是java内存模型2、主内存与本地内存 七、Volatile关键字

1、什么是Volatile2、验证案例3、Volatile与Synchronized区别

前言 一、线程安全问题

当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题但是做读操作是不会发生数据冲突问题线程安全解决办法:1、内置锁(synchronized);2、显示锁(lock锁)

二、内置锁(synchronized)

锁的特征:只能有一个线程进行使用

保证线程原子性,当线程进入方法的时候,自动获取锁一旦锁被其他线程获取到后,其他的线程就会等待 锁的释放:程序执行完毕之后,就会把锁释放内置锁也是互斥锁,但是它会降低程序的效率synchronized的两种使用方式

a)同步方法b)同步代码块

1、非静态同步方法

非静态同步方法使用的是this锁

class ThreadDemo01 implements Runnable {
    private int count = 100;

    @Override
    public void run() {
        while (count > 0) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                // TODO: handle exception
            }
            sale();
        }
    }

    public synchronized void sale() {
        if (count > 0) {
            System.out.println(Thread.currentThread().getName() + ",出售" + (100 - count + 1) + "张票");
            count--;
        }
    }
}

public class App {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo01 threadDemo01 = new ThreadDemo01();
        Thread t1 = new Thread(threadDemo01, "窗口1");
        Thread t2 = new Thread(threadDemo01, "窗口2");
        t1.start();
        Thread.sleep(40);
        t2.start();
    }
}
2、同步代码块

注意:使用同步的时候,锁一定要是相同的

1、同一对象的多线程threadDemo01

class ThreadDemo01 implements Runnable {
    private int count = 100;
    private Object oj = new Object();

    @Override
    public void run() {
        while (count > 0) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                // TODO: handle exception
            }
            sale();
        }
    }

    public void sale() {
        synchronized (oj) {
            if (count > 0) {
                System.out.println(Thread.currentThread().getName() + ",出售" + (100 - count + 1) + "张票");
                count--;
            }
        }
    }
}

public class App {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo01 threadDemo01 = new ThreadDemo01();
        Thread t1 = new Thread(threadDemo01, "窗口1");
        Thread t2 = new Thread(threadDemo01, "窗口2");
        t1.start();
        Thread.sleep(40);
        t2.start();
    }
}

2、不同对象的多线程threadDemo01,threadDemo02

class ThreadDemo01 implements Runnable {
    private static int count = 100;
    private static Object oj = new Object();

    @Override
    public void run() {
        while (count > 0) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                // TODO: handle exception
            }
            sale();
        }
    }

    public void sale() {
        synchronized (oj) {
            if (count > 0) {
                System.out.println(Thread.currentThread().getName() + ",出售" + (100 - count + 1) + "张票");
                count--;
            }
        }
    }
}

public class App {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo01 threadDemo01 = new ThreadDemo01();
        ThreadDemo01 threadDemo02 = new ThreadDemo01();
        Thread t1 = new Thread(threadDemo01, "窗口1");
        Thread t2 = new Thread(threadDemo02, "窗口2");
        t1.start();
        Thread.sleep(40);
        t2.start();
    }
}
3、静态同步方法

非静态同步方法 -> 使用this锁:synchronized (this)静态同步方法 -> 使用当前class字节码文件:synchronized (ThreadDemo01.class)

    public static synchronized void sale() {
        if (count > 0) {
            System.out.println(Thread.currentThread().getName() + ",出售" + (100 - count + 1) + "张票");
            count--;
        }
    }
三、多线程死锁

什么是多线程死锁

同步中嵌套同步,导致锁无法释放

	public synchronized void sale() {
		synchronized (oj) {
			try {
				Thread.sleep(10);
			} catch (Exception e) {

			}
			if (trainCount > 0) {
				System.out.println(Thread.currentThread().getName() + "," + "出售第" + (100 - trainCount + 1) + "票");
				trainCount--;
			}
		}
	}
}
四、Threadlocal 1、什么是Threadlocal

ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本

2、Threadlocal使用
package com.sjyl;

class Res {
    public static ThreadLocal threadLocal = new ThreadLocal() {
        protected Integer initialValue() {
            return 0;
        };
    };

    public Integer getNumber() {
        int count = threadLocal.get() + 1;
        threadLocal.set(count);
        return count;

    }
}

public class App extends Thread {
    private Res res;

    public App(Res res) {
        this.res = res;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + "," + res.getNumber());
        }
    }

    public static void main(String[] args) {
        Res res = new Res();
        App t1 = new App(res);
        App t2 = new App(res);
        t1.start();
        t2.start();
    }
}

每个线程都有自己的count计数对象,互不影响

五、多线程有三大特性 1、原子性

即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

一个很经典的例子就是银行账户转账问题:

比如从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。这2个操作必须要具备原子性才能保证不出现一些意外的问题。

2、可见性

当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值

若两个线程在不同的cpu,那么线程1改变了i的值还没刷新到主存,线程2又使用了i,那么这个i值肯定还是之前的,线程1对变量的修改线程没看到这就是可见性问题

3、有序性

程序执行的顺序按照代码的先后顺序执行

一般来说处理器为了提高程序运行效率,可能会对输入代码进行优化它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的

int a = 10;    //语句1
int r = 2;    //语句2
a = a + 3;    //语句3
r = a*a;     //语句4
//因为重排序,可能执行顺序为 2-1-3-4,1-3-2-4
//但绝不可能 2-1-4-3,因为这打破了依赖关系
//显然重排序对单线程运行是不会有任何问题
//而多线程就不一定了,所以我们在多线程编程时就得考虑这个问题了。
六、Java内存模型 1、什么是java内存模型

共享内存模型指的就是Java内存模型(简称JMM)

JMM决定一个线程对共享变量的写入时,能对另一个线程可见

这里要区分清楚“内存模型”和“内存结构”

内存模型:jmm,多线程相关的内存结构:jvm,内存结构

2、主内存与本地内存

JMM定义了线程和主内存之间的抽象关系

主内存:共享变量

线程之间的共享变量存储在主内存(main memory)中 本地内存:共享变量的副本

每个线程都有一个私有的本地内存(local memory)本地内存中存储了该线程以读/写共享变量的副本

如下图

多线程对count实现++的时候,并不是直接对共享变量count进行++而是先对自己的本地内存count进行++,然后再刷新到主内存中

a)起始的时候主内存count=0,这时候t1和t2线程同时执行b)此时t1的本地内存count=1,t2的本地内存count=1c)这时候t1和t2同时刷新到主内存中d)此时的主内存count=1

七、Volatile关键字 1、什么是Volatile

可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。

项目中什么时候使用Volatile

只要是全局共享变量,全部都加上Volatile关键字

2、验证案例

flag不加Volatile关键字,线程会一直运行,不会暂停

因为flag是在主线程中修改为false的这时候并不会同步到主内存中子线程中本地内存的flag还是true flag加Volatile关键字,3秒之后线程就停止了

class ThreadDemo004 extends Thread {
    public volatile boolean flag = true;

    @Override
    public void run() {
        System.out.println("线程开始...");
        while (flag) {

        }
        System.out.println("线程結束...");
    }

    public void setRuning(boolean flag) {
        this.flag = flag;
    }
}

public class App {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo004 threadDemo004 = new ThreadDemo004();
        threadDemo004.start();
        Thread.sleep(3000);
        threadDemo004.setRuning(false);
        System.out.println("flag已經改為false");
        Thread.sleep(1000);
        System.out.println("flag:" + threadDemo004.flag);
    }
}
3、Volatile与Synchronized区别

volatile虽然具有可见性但是并不能保证原子性性能方面

synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率volatile关键字在某些情况下性能要优于synchronized

要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/754292.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号