zoukankan      html  css  js  c++  java
  • 多线程编程-- part 3 多线程同步->synchronized关键字

        多线程同时访问一个资源,可以会产生不可预料的结果,所以为这个资源加锁,访问资源的第一个线程为其加锁后,其他线程便不能在使用那个资源,直到锁被解除。

    举个例子:

        存款1000元,能取出800的时候我就取800,当我同时用两个线程调用这个取钱操作时,有时可以取出1600元

    static class HelloRunable implements Runnable{
             private int money = 1000;
    
             //取出800元
              int getMoney() {
                 System.out.println("开始" + money);
                 if(money > 800) {
                     try {
                         Thread.sleep(100);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     money -= 800;
                     System.out.println("我取了800元" + money);
                 }
                 System.out.println("结束" + money);
                 return money;
             }
    
            @Override
            public void run() {
                money = getMoney();
            }
        }
    
    
        public static void main(String[] args) {
            HelloRunable helloRunable = new HelloRunable();
            Thread t = new Thread(helloRunable);
            Thread t1 = new Thread(helloRunable);
            t.start();
            t1.start();
    
        }
    

      

    synchronized:

    所以我们引入了同步机制,在取钱方法前面加入了synchronized关键字,该方法称为同步方法,输出结果为

         java中每个对象都有一个锁,或者叫做监视器(monitor),当一个线程访问某个对象的synchronized方法时,将该对象上锁,其他任何线程都无法再去访问该对象的synchronized方法,直到之前的那个线程执行完方法之后,才会将对象锁释放,其他线程才可以在用该对象的synchronized方法。  注:这是给对象上锁,如果是不同的对象则该对象之间没有限制关系。

         如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到了synchronized方法,那么在该方法没有执行完前,其他线程是无法访问该对象的任何synchronized方法的。

    例如:

     public static void main(String[] args)
        {
            Example example = new Example();
    
            Thread t1 = new Thread1(example);
            Thread t2 = new Thread2(example);
    
            t1.start();
            t2.start();
        }
    
    
    
        static class Example
        {
            public synchronized void execute()
            {
                for (int i = 0; i < 20; ++i)
                {
                    try
                    {
                        Thread.sleep((long) Math.random() * 1000);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println("Hello: " + i);
                }
            }
    
            public  void execute2()
            {
                for (int i = 0; i < 20; ++i)
                {
                    try
                    {
                        Thread.sleep((long) Math.random() * 1000);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println("World: " + i);
                }
            }
    
        }
    
        static class Thread1 extends Thread
        {
            private Example example;
    
            public Thread1(Example example)
            {
                this.example = example;
            }
    
            @Override
            public void run()
            {
                example.execute();
            }
    
        }
    
        static class Thread2 extends Thread
        {
            private Example example;
    
            public Thread2(Example example)
            {
                this.example = example;
            }
    
            @Override
            public void run()
            {
                example.execute2();
            }
    
        }
    

      

    当加上synchronized后,当同步方法未执行完时另一个同步方法不会执行

    静态的同步方法

      当一个synchronized关键字修饰的方法同时被static修饰,非静态的同步方法会将对象上锁,但是静态方法不属于对象,而是属于类,他会将这个方法所在的类的Class对象上锁。

     public static void main(String[] args)
        {
            Example example = new Example();
    
            Thread t1 = new Thread1(example);
    
            example = new Example();
            Thread t2 = new Thread2(example);
    
            t1.start();
            t2.start();
        }
    
    
    
        static class Example
        {
            public static synchronized void execute()
            {
                for (int i = 0; i < 20; ++i)
                {
                    try
                    {
                        Thread.sleep((long) Math.random() * 1000);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println("Hello: " + i);
                }
            }
    
            public static synchronized void execute2()
            {
                for (int i = 0; i < 20; ++i)
                {
                    try
                    {
                        Thread.sleep((long) Math.random() * 1000);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println("World: " + i);
                }
            }
    
        }
    
        static class Thread1 extends Thread
        {
            private Example example;
    
            public Thread1(Example example)
            {
                this.example = example;
            }
    
            @Override
            public void run()
            {
                example.execute();
            }
    
        }
    
        static class Thread2 extends Thread
        {
            private Example example;
    
            public Thread2(Example example)
            {
                this.example = example;
            }
    
            @Override
            public void run()
            {
                example.execute2();
            }
    
        }
    

    不加静态方法方法:

       当某个synchronized方法是static的,那么当线程访问该方法时,他锁的并不是synchronized方法所在的对象,而是synchronized方法所在类的对应的class对象(java中,一个类无论有多少对象,这些对象会对应唯一的class对象,因此当线程分别访问一个类的两个对象的的两个static synchronized方法时,他们的执行顺序也是有顺序的,也就是说一个线程先去执行,执行完释放锁,另一个线程再去执行)

    synchronized代码块

    synchronized(object) {

    }

      表示的是在执行过程中会将object对象上锁(这个对象可以使任意类的对象,也可以使用this),可以自行规定上锁对象

    public class test {
        public static void main(String[] args) {
            Example example = new Example();
    
            Thread t1 = new Thread1(example);
            Thread t2 = new Thread2(example);
    
            t1.start();
            t2.start();
        }
    
    }
    
        class Example {
            private Object object = new Object();
    
            public void execute() {
                System.out.println("我开始了");
                synchronized (object) {
                    for (int i = 0; i < 20; ++i) {
                        try {
                            Thread.sleep((long) Math.random() * 1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("Hello: " + i);
                    }
    
                }
    
            }
    
            public void execute2() {
                System.out.println("我也开始了");
                synchronized (object) {
                    for (int i = 0; i < 20; ++i) {
                        try {
                            Thread.sleep((long) Math.random() * 1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("World: " + i);
                    }
    
                }
    
            }
    
        }
    
        class Thread1 extends Thread {
            private Example example;
    
            public Thread1(Example example) {
                this.example = example;
            }
    
            @Override
            public void run() {
                example.execute();
            }
    
        }
    
        class Thread2 extends Thread {
            private Example example;
    
            public Thread2(Example example) {
                this.example = example;
            }
    
            @Override
            public void run() {
                example.execute2();
            }
    
        }
    

        可以看到除了synchronized代码块里的方法,其他是不会同步执行的。

      synchronized方法是一种粗粒度的并发控制,某一时刻,只能有一个线程执行synchronized方法。

      synchronized块则是细粒度的并发控制,只会将块中的代码同步,方法内的其他代码是可以被多个线程同时访问到的

  • 相关阅读:
    集合合并
    非递减有序集合合并
    有序的双链表的实现
    单链表的实现
    构造有序的单链表
    约瑟夫环问题
    javaweb学习笔记
    Intellij IDEA快捷键
    JAVA:创建类和对象
    JAVA:成员变量和局部变量的区别
  • 原文地址:https://www.cnblogs.com/jijiji/p/6900744.html
Copyright © 2011-2022 走看看