IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 线程安全的部分知识 -> 正文阅读

[Java知识库]线程安全的部分知识

package cn.tan.phenomenon;

public class Main {
    // 定义一个共享的数据 —— 静态属性的方式来体现
    static int r = 0;

    // 定义加减的次数
    // COUNT 越大,出错的概率越大;COUNT 越小,出错的概率越小
    static final int COUNT = 1000_000_00;

    // 定义两个线程,分别对 r 进行 加法 + 减法操作
    static class Add extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < COUNT; i++) {
                r++;
            }
        }
    }

    static class Sub extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < COUNT; i++) {
                r--;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Add add = new Add();
        add.start();

        Sub sub = new Sub();
        sub.start();

        add.join();
        sub.join();

        // 理论上,r 被加了 COUNT 次,也被减了 COUNT 次
        // 所以,结果应该是 0
        System.out.println(r);
    }
}

以上代码是线程安全的吗?

单看代码是没有问题的,可是结果没能达到预期为0的结果

线程不安全的原因

?再看上面的例子,同时操作了一个静态属性r,因此就可能发生错误。

count越大,线程执行需要跨时间片的概率越大,导致中间出错的概率越大。

2.作为程序员如何考虑线程安全的问题


1.尽可能让几个线程之间不做数据共享,各干各的。就不需要考虑线程安全问题了
比如对一个数组的归并排序:4个线程虽然处理的是同一个数组,但提前划好范围,各做各的,就没问题了
2.如果非要有共享操作,尽可能不去修改,而是只读操作
static?final?int?COUNT=;即使多个线程同时使用这个COUNT也无所谓的
3.一定会出现线程问题了,问题的原因从系统角度讲:
1.原子性被破坏了
2.由于内存可见性问题,导致某些线程读取到“脏(dity)”
3.由于代码重排序导致的线程之间关于数据的配合出问题了
原子性就是一个操作要么全部完成,要么都不完成。

?

锁:

synchronized


?关于类名.class的一个知识,每个被加载的类有且仅有一个class对象

?


synchronized修饰两种方法的区别

?互斥现象的产生

?(1)当多个线程都有加锁操作的时候(2)并且申请的是同一把锁的时候,锁的是同一个对象

现代java并发编程之JUC包

?关于lock一些案例的讲解

(1)?

public class Main1 {
    private static final Lock lock = new ReentrantLock();

    static class MyThread extends Thread {
        @Override
        public void run() {
            lock.lock();
            System.out.println("子线程进入临界区");     // 理论上,这句代码永远到达不了
        }
    }

    public static void main(String[] args) throws InterruptedException {
        lock.lock();

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

        t.join();
    }
}

主线程加锁,之后子线程想要申请锁申请不到。

(2)

public class Main2 {
    private static final Lock lock = new ReentrantLock();

    static class MyThread extends Thread {
        @Override
        public void run() {
            lock.lock();
            System.out.println("子线程进入临界区");     // 理论上,这句代码永远到达不了
        }
    }

    public static void main(String[] args) throws InterruptedException {
        lock.lock();

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

        TimeUnit.SECONDS.sleep(2);

        t.interrupt();      // 尝试让子线程停下来,但实际会徒劳无功

        t.join();
    }
}

这里让主线程睡两秒,尝试给子线程一个停止的信号,但是没有一个让他停止的动作,也没有用,锁仍然没有释放,仍然死锁。

(3)

public class Main3 {
    private static final Lock lock = new ReentrantLock();

    static class MyThread extends Thread {
        @Override
        public void run() {
            try {
                lock.lockInterruptibly();
                System.out.println("子线程进入临界区");     // 理论上,这句代码永远到达不了
            } catch (InterruptedException e) {
                System.out.println("收到停止信号,停止运行");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        lock.lock();

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

        TimeUnit.SECONDS.sleep(2);

        t.interrupt();

        t.join();
    }
}

这个案例和上一个的区别就是尝试让子线程停止,子线程用的是一个允许被中断的锁,这里再调用interrupt()方法就会以一个异常的形式来处理

(4)

package cn.tan.locks;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main4 {
    private static final Lock lock = new ReentrantLock();

    static class MyThread extends Thread {
        @Override
        public void run() {
            boolean b = lock.tryLock();
            if (b == true) {
                // 加锁成功了
                System.out.println("加锁成功");
                System.out.println("子线程进入临界区");     // 理论上,这句代码永远到达不了
            } else {
                System.out.println("加锁失败");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        lock.lock();

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

        TimeUnit.SECONDS.sleep(2);

        t.interrupt();      // 尝试让子线程停下来,但实际会徒劳无功

        t.join();
    }
}

这一个呢,用了trylock,尝试加锁,但是一直被主线程占用,所以返回一个false,加锁失败。

(5)

package cn.tan.locks;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Main5 {
    private static final Lock lock = new ReentrantLock();

    static class MyThread extends Thread {
        @Override
        public void run() {
            boolean b = false;
            try {
                b = lock.tryLock(5, TimeUnit.SECONDS);
                if (b == true) {
                    // 加锁成功了
                    System.out.println("加锁成功");
                    System.out.println("子线程进入临界区");
                } else {
                    System.out.println("5s 之后加锁失败");
                }
            } catch (InterruptedException e) {
                System.out.println("被人打断了");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        lock.lock();

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

        TimeUnit.SECONDS.sleep(2);

        t.interrupt();
        lock.unlock();


        t.join();
    }
}

?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-27 11:11:09  更:2022-04-27 11:12:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:14:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码