Java进阶学习笔记(五) 多线程编程(二)线程同步安全问题:synchronized的作用与应用、线程安全的类

一. synchronized简介

synchronized用于并发编程中,可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块

二. 锁方法

先通过runnable实现一个简单的多线程,用synchronized修饰increase
我们的目标是通过两个线程,使用 i++,让 i 增长至20000

public class SynchronizedTest implements Runnable {
    static int  i = 0;

    public synchronized void increase() {
        i++;
    }

    public int getI() {
        return i;
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000; j++) {
            increase();
        }
    }
}

我们在同时开启这两个线程运行,代码如下所示:

    public static void main(String[] args) {
        SynchronizedTest synchronizedTest = new SynchronizedTest();
        Thread t1 = new Thread(synchronizedTest);
        Thread t2 = new Thread(synchronizedTest);
        t1.start();
        t2.start();
        try {
        // join是阻塞主进程,直到线程结束再运行后面的代码
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(synchronizedTest.getI());
    }

结果如下所示(I一定为20000):
在这里插入图片描述
当我们取消掉synchronized,此时SynchronizedTest的代码如下所示:

public class SynchronizedTest implements Runnable {
    static int  i = 0;

    public void increase() {//仅有此处不同,少了synchronized
        i++;
    }

    public int getI() {
        return i;
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000; j++) {
            increase();
        }
    }
}

main函数不变化,再次运行,执行结果如下所示(I会变化):
在这里插入图片描述
说明在没有synchronized的时候,线程可能同时执行increase,使得
线程一的increase:读取 i,i = i + 1
线程二的increase:读取 i,i = i + 1
读取的 i 值相等,使得 i 没有正确的累加。

加了synchronized之后,一个线程需要等待另外一个线程完成后,才能调用
increase,这就使得 i 能够正确变为 20000

三. 代码块

3.1 锁变量(成员锁)

锁的对象是变量。
由于synchronized的参数要求是object,所以原本int i属于基础类型,并不属于object,此处需要将int换成Integer

    private static Integer  i = 0;

    public void increase() {//仅有此处不同,少了synchronized
        synchronized (i) {
            i++;
        }
    }
3.2 锁当前实例(实例对象锁)

this 代表当前实例

    public void increase() {//仅有此处不同,少了synchronized
        synchronized (this) {
            i++;
        }
    }
3.3 锁当前类(Class对象锁)
    public void increase() {//仅有此处不同,少了synchronized
        synchronized (SynchronizedTest.class) {
            i++;
        }
    }

四、线程安全的类

线程不安全线程安全其他区别
HashMapHashtableHashMap可以存放 null,Hashtable不能存放null
StringBuilderStringBufferStringBuilder拼接字符串更快(因为少了同步)
ArrayListVector

4.1 把非线程安全的集合转换为线程安全

ArrayList是非线程安全的,换句话说,多个线程可以同时进入一个ArrayList对象的add方法

借助Collections.synchronizedList,可以把ArrayList转换为线程安全的List。

与此类似的,还有HashSet,LinkedList,HashMap等等非线程安全的类,都通过工具类Collections转换为线程安全的

    public static void main(String[] args) {
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = Collections.synchronizedList(list1);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值