欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

并发编程一:Synchronized的使用及分析

程序员文章站 2022-06-21 10:55:37
...

本文主要为了分析Synchronized的使用及分析,全程例子跟踪讲解,妈妈再也不用担心你的编程。(Lock等后续会讲解)

首先我们先看个例子:

public class MyThread implements Runnable{
    // 定义一个变量
    static int i=0;
    // 方法 使内部变量 加加递增
    public void add(){
        i++;
    }

    // 实现Runnable重写线程run方法
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            add();
        }
    }

    // 主函数 程序入口(我好像多余写,但是我就想写,怎样?)
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        // 创建一个线程 t1
        Thread t1=new Thread(myThread);
        // 创建一个线程 t2
        Thread t2=new Thread(myThread);
        // 启动线程
        t1.start();
        t2.start();
        // join不知道的自己百度,简单解释下:调用join的线程必须执行完才能继续执行主线程,此处也可以用sleep
        t1.join();t2.join();
        System.out.printf("结果:"+i);
    }
}

3次运行结果:

并发编程一:Synchronized的使用及分析并发编程一:Synchronized的使用及分析 并发编程一:Synchronized的使用及分析

从结果上我们可以发现,有一次结果是正确的,俩次不正确。这就是线程不安全的。下面我们在add方法上添加synchronized再进行测试

public class MyThread implements Runnable{
    // 定义一个变量
    static int i=0;
    // 方法 使内部变量 加加递增
    public synchronized void add(){
        i++;
    }

    // 实现Runnable重写线程run方法
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            add();
        }
    }

    // 主函数 程序入口(我好像多余写,但是我就想写,怎样?)
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        // 创建一个线程 t1
        Thread t1=new Thread(myThread);
        // 创建一个线程 t2
        Thread t2=new Thread(myThread);
        // 启动线程
        t1.start();
        t2.start();
        // join不知道的自己百度,简单解释下:调用join的线程必须执行完才能继续执行主线程,此处也可以用sleep
        t1.join();t2.join();
        System.out.printf("结果:"+i);
    }
}

继续看3次运行结果:

并发编程一:Synchronized的使用及分析并发编程一:Synchronized的使用及分析并发编程一:Synchronized的使用及分析 

哈哈哈 我们会发现 全都是 20000了,都是正确的结果。看来添加synchronized 可以保证线程的安全。你以为这就完事了,刚刚开始而已。来我们再来看个例子:

public class MyThread implements Runnable{
    // 定义一个变量
    static int i=0;
    // 方法 使内部变量 加加递增
    public synchronized void add(){
        i++;
    }

    // 实现Runnable重写线程run方法
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            add();
        }
    }

    // 主函数 程序入口(我好像多余写,但是我就想写,怎样?)
    public static void main(String[] args) throws InterruptedException {
        //MyThread myThread = new MyThread();
        // 创建一个线程 t1
        Thread t1=new Thread(new MyThread());
        // 创建一个线程 t2
        Thread t2=new Thread(new MyThread());
        // 启动线程
        t1.start();
        t2.start();
        // join不知道的自己百度,简单解释下:调用join的线程必须执行完才能继续执行主线程,此处也可以用sleep
        t1.join();t2.join();
        System.out.printf("结果:"+i);
    }
}

这段代码add方法上也添加了synchronize,但是我们为每个线程创建了一个MyThread对象而不是上面的两个线程用一个对象。

下面继续看3次的运行结果:

并发编程一:Synchronized的使用及分析并发编程一:Synchronized的使用及分析并发编程一:Synchronized的使用及分析 

卧槽了吧,哈哈怎么方法加了synchonized 线程还不安全。这里面就涉及到了对象锁和类锁的问题。有空再写吧写这玩意浪费时间。直接总结下吧  static synchonized和synchonized (类名.class) 可以解决问题  这俩都是类锁,类只有一个文件所以只能有一个线程获取到锁所以线程安全,至于对象锁也不是没用对象锁保证的是单个对象操作的并发问题

相关标签: 线程 Thread