Java(十八) -- 线程同步

目录

线程同步

非线程同步

线程同步

线程安全的单例模式

单线程模式下的单例模式

多线程模式下的单例模式

优化 

线程同步

并发、并行


线程同步

        Java 中允许多线程并行访问,同一时间段内多个线程同时完成各自的操作。

        多个线程同时操作同一个共享数据时,可能会导致数据不准确的问题。

        使用线程同步可以解决上述问题。

        可以通过 synchronized 关键字修饰方法实现线程同步,每个 Java 对象都有一个内置锁,内置锁会保护使用 synchronized 关键字修饰的方法,要调用该方法就必须先获得锁,否则就处于阻塞状态。

非线程同步

public class Account implements Runnable {
​
    private static int num;
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        //1.num++操作
        num++;
        //2.休眠1毫秒
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //3.打印输出
        System.out.println(Thread.currentThread().getName()+"是当前的第"+num+"位访问");
    }
}

线程同步

public class Account implements Runnable {
​
    private static int num;
    
    @Override
    public synchronized void run() {
        // TODO Auto-generated method stub
        //1.num++操作
        num++;
        //2.休眠1毫秒
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //3.打印输出
        System.out.println(Thread.currentThread().getName()+"是当前的第"+num+"位访问");
    }   
}
public class Test {
    public static void main(String[] args) {
        Account account = new Account();
        Thread t1 = new Thread(account,"张三");
        Thread t2 = new Thread(account,"李四");
        t1.start();
        t2.start();
    }
}

        synchronized 关键字可以修饰实例方法,也可以修饰静态方法,两者在使用的时候是有区别的。

public class SynchronizedTest {
    
    public static void main(String[] args) {
        for(int i = 0; i < 5;i++) {
            Thread thread = new Thread(new Runnable() {
                
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    SynchronizedTest.test();
                }
            });
            thread.start();
        }
    }
    
    /**
     * 先输出start...
     * 间隔1s
     * 再输出end...
     * 输出start...
     * ...
     */
    public synchronized static void test() {
        //1.输出start
        System.out.println("start......");
        //2.休眠
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //3.输出end
        System.out.println("end......");
    }
    
}
    synchronized 修饰非静态方法
public class SynchronizedTest2 {
    public static void main(String[] args) {
        for(int i=0;i<5;i++) {
            Thread thread = new Thread(new Runnable() {
                
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    SynchronizedTest2 synchronizedTest2 = new SynchronizedTest2();
                    synchronizedTest2.test();
                }
            });
            thread.start();
        }
    }
    
    public synchronized void test() {
        System.out.println("start......");
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("end......");
    }
}

        给实例方法(非静态方法)添加 synchronized 关键字并不能实现线程同步

        线程同步的本质是锁定多个线程所共享的资源,synchronized 还可以修饰代码块,会为代码块加上内置锁,从而实现同步。

public class SynchronizedTest3 {
    
    public static void main(String[] args) {
        for(int i=0;i<5;i++) {
            Thread thread = new Thread(new Runnable() {
                
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    SynchronizedTest3.test();
                }
            });
            thread.start();
        }
    }
    
    public static void test() {
        
        synchronized (SynchronizedTest3.class) {
            System.out.println("start...");
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("end...");
        }
        
    }
​
}

        如何判断线程同步或是不同步?

                找到关键点:锁定的资源在内存中是一份还是多份?一份大家需要排队,线程同步,多份(一人一份),线程不同步。

                无论是锁定方法还是锁定对象,锁定类,只需要分析这个方法、对象、类在内存中有几份即可。

                对象一般都是多份

                类一定是一份

                方法就看是静态方法还是非静态方法,静态方法一定是一份,非静态方法一般是多份

线程安全的单例模式

        单例模式是一种常见的软件设计模式,核心思想一个类只有一个实例对象

        JVM:栈内存、堆内存

单线程模式下的单例模式

public class SingletonDemo {
​
  private static SingletonDemo singletonDemo;
​
  private SingletonDemo() {
    System.out.println("创建了SingletonDemo...");
  }
​
  public static SingletonDemo getInstance() {
    if(singletonDemo == null) {
      singletonDemo = new SingletonDemo();
    }
    return singletonDemo;
  }
}

多线程模式下的单例模式

public class SingletonDemo {
​
  private static SingletonDemo singletonDemo;
​
  private SingletonDemo() {
    System.out.println("创建了SingletonDemo...");
  }
​
  public synchronized static SingletonDemo getInstance() {
    if(singletonDemo == null) {
      singletonDemo = new SingletonDemo();
    }
    return singletonDemo;
  }
}

优化 

        双重检测,synchronized 修饰代码块。

                1、线程同步是为了实现线程安全,如果只创建一个对象,那么线程就是安全的。

                2、如果 synchronized 锁定的是多个线程共享的数据(同一个对象),那么线程就是安全的。

                3、

public class SingletonDemo {
    
    private volatile static SingletonDemo singletonDemo;
    
    private SingletonDemo() {
        System.out.println("创建了SingletonDemo...");
    }
    
    public static SingletonDemo getInstance() {
        if(singletonDemo == null) {
            synchronized (SingletonDemo.class) {
                if(singletonDemo == null) {
                    singletonDemo = new SingletonDemo();
                }
            }
        }
        return singletonDemo;
    }
}

        volatile 的作用是可以使内存中的数据对线程可见

        主内存对线程是不可见的,添加 volatile 关键字之后,主内存对线程可见

线程同步

并发、并行

        使用并发编程的目的?

                为了充分利用计算机的资源,提高性能,企业以盈利为目的。

        并发多个线程访问同一个共享资源,前提是计算机是单核 CPU,多个线程不是同时在访问,而是交替进行,只是因为 CPU 运行速度太快,看起来是同时在运行。

        并行:多核 CPU,多个线程是真正的同时在运行,各自占用不同的 CPU,相互之间没有影响,也不会争夺资源。

        Java 默认线程有两个,main(主线程),GC(垃圾回收机制)

        synchronized 关键字实现线程同步,让在访问同一个资源的多个线程排队去完成业务,避免出现数据错乱的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug 消灭师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值