zoukankan      html  css  js  c++  java
  • java多线程学习-同步(synchronized)

    (示例都是网上视频的)

    假如两个线程同时调用一个方法输出字符串

    public class SynchronizedTest extends Thread {
        public static void main(String[] args) {
            final SynchronizedTest st = new SynchronizedTest();
            new Thread(new Runnable() {
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        st.outputStr("this is test");
                    }
                }
            }).start();
            new Thread(new Runnable() {
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        st.outputStr("okokokokokok");
                    }
                }
            }).start();
        }
        
        
        public void outputStr(String str){
            for(int i=0;i<str.length();i++){
                System.out.print(str.charAt(i));
            }
            System.out.println();
        }
    }

    输出:

    this is test
    okokokokokok
    this is test
    okokokokokok
    this is test
    okokothis is test
    kokokok
    tokokokokokok
    his is test
    okokokokokok
    this is test
    okokthisokokokok
    is test
    okothkoiskokokok
    is test
    okokokothis is test
    kokok
    this iokokokokokok
    s test
    okokokothiskokok
    is test
    okokokokokokthis
    is test
    okthisok is tokokokoest

    可以看出来,一开始输出还没问题,后来输出就乱了。

    解决方法就是加上同步方法即在outputStr方法上加上同步关键字synchronized即可

        public synchronized void outputStr(String str){
            for(int i=0;i<str.length();i++){
                System.out.print(str.charAt(i));
            }
            System.out.println();
        }

    synchronized :

    Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。

    当然synchronized不仅可以用在方法上,还可以用在对象上。

    1.用在String上

    public class SynchronizedTest2 {
    
        public static void main(String[] args) {
            final SynchronizedTest2 t2 = new SynchronizedTest2();
            new Thread(new Runnable() {
                
                public void run() {
                    
                    while(true){
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        t2.outputStr("thread-1");
                    }
                }
            }).start();
            
            new Thread(new Runnable() {
                
                public void run() {
                    
                    while(true){
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        t2.outputStr("thread-2");
                    }
                }
            }).start();
        }
        
        public void outputStr(String threadName){
            String str = "123";
            synchronized(str){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName + " - "+System.currentTimeMillis()/1000);
            }
        }
    }

    输出:

    thread-1 - 1475373023
    thread-2 - 1475373024
    thread-1 - 1475373025
    thread-2 - 1475373026
    thread-1 - 1475373027

    可以看出,每一秒只有一个线程在运行,但是也不觉得是thread-1运行下,thread-2运行下,随机的。对字符串同步也可以,但是同步的必须是同一个对象才能互斥。

    如:将outputStr方法改为
    public void outputStr(String threadName){
            String str = "123";
            synchronized(threadName){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName + " - "+System.currentTimeMillis()/1000);
            }
        }

     这次synchronized里面同步的是threadName参数了

    输出:

    thread-1 - 1475373333
    thread-2 - 1475373333
    thread-1 - 1475373334
    thread-2 - 1475373334
    thread-1 - 1475373335
    thread-2 - 1475373335
    thread-1 - 1475373336
    thread-2 - 1475373336

    可以看出同一秒中两个线程都运行了,这里面两个线程就没有互斥。

     2.用在this上
    把outputStr方法改为
    public void outputStr(String threadName){
            String str = "123";
            synchronized(this){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName + " - "+System.currentTimeMillis()/1000);
            }
        }

    这时候调用同一SynchronizedTest2对象的线程在这个方法里都会互斥

    但是如果把main方法改成这样

    public class SynchronizedTest2 {
    
        public static void main(String[] args) {
            new Thread(new Runnable() {
                public void run() {
                    SynchronizedTest2 t2 = new SynchronizedTest2();
                    while(true){
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        t2.outputStr("thread-1");
                    }
                }
            }).start();
            
            new Thread(new Runnable() {
                public void run() {
                    SynchronizedTest2 t2 = new SynchronizedTest2();
    
                    while(true){
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        t2.outputStr("thread-2");
                    }
                }
            }).start();
        }
        
        public void outputStr(String threadName){
            String str = "123";
            synchronized(this){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName + " - "+System.currentTimeMillis()/1000);
            }
        }
    }

    即每个线程都使用不同的SynchronizedTest2对象,这时输出:

    thread-2 - 1475376542
    thread-1 - 1475376542
    thread-1 - 1475376543
    thread-2 - 1475376543
    thread-1 - 1475376544
    thread-2 - 1475376544
    thread-1 - 1475376545
    thread-2 - 1475376545

    可以看出此时两个线程并没有互斥。所以同步this只有使用同一个对象才会互斥。

    3.用在类的字节码上

    把outputStr方法改为

    public void outputStr(String threadName){
            String str = "123";
            synchronized(SynchronizedTest2.class){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName + " - "+System.currentTimeMillis()/1000);
            }
        }

    这时不管main方法里面的两个线程使用是同一个SynchronizedTest2对象还是不同的对象,在调用这个方法的时候,都能互斥,不会同时运行。可能是因为字节码对象只有一个吧。

    其实将synchronized放在方法上,好像和这样同步一样。

    synchronized关键字暂时只想到这么多,写的有点乱。

  • 相关阅读:
    element input number e
    地图 scatter 自定义图片
    地图某一个区域设置高亮
    echarts 获取县级json
    echarts map 阴影(重叠)
    echarts 渐变色
    echarts tooltip 超出处理
    npm 下载 zip
    axios post 下载文件
    书签 css
  • 原文地址:https://www.cnblogs.com/Iqiaoxun/p/5927286.html
Copyright © 2011-2022 走看看