zoukankan      html  css  js  c++  java
  • java 多线程 synchronized与lock的通信机制等问题,结合相应实例说明

    1. 利用多线程实现如下需求:

    写两个线程,一个线程打印1~52,另一个线程打印A~Z,打印顺序是12A34B...5152Z;

    2. 使用synchronized 实现 

    public class Test13
    {
        public synchronized void printNum(){
            
    //        System.out.println(Thread.currentThread().getName() + "num:	" + Thread.currentThread().getId());
            for (int i = 1; i <= 52; i++)
            {
                System.out.print(i + ",");
                if (i%2 == 0)
                {
                    try
                    {
                        this.notify();
                        this.wait();
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }
        public synchronized void printLetter(){
    //        System.out.println(Thread.currentThread().getName() + "letter:	" + Thread.currentThread().getId());
            for (int i = 0; i < 26; i++)
            {
                try
                {
                    System.out.println((char)('A'+i));
                    this.notify();
                    if (i != 25)
                    {
                        this.wait();
                    }
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }

     

    public class Test12
    {
        public static void main(String[] args) throws InterruptedException
        {
            //写两个线程,一个线程打印1~52,另一个线程打印A~Z,打印顺序是12A34B...5152Z;
    //        Test13 test = new Test13();
            Test14 test = new Test14();
            
            Thread t1 = new Thread(new Runnable()
            {
                
                @Override
                public void run()
                {
                    try
                    {
                        test.printNum();
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            });
            Thread t2 = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    test.printLetter();
                }
            });
            
            t1.start();
            t2.start();
        }
    }

     结果:

    1,2,A
    3,4,B
    5,6,C
    7,8,D
    9,10,E
    11,12,F
    13,14,G
    15,16,H
    17,18,I
    19,20,J
    21,22,K
    23,24,L
    25,26,M
    27,28,N
    29,30,O
    31,32,P
    33,34,Q
    35,36,R
    37,38,S
    39,40,T
    41,42,U
    43,44,V
    45,46,W
    47,48,X
    49,50,Y
    51,52,Z
    View Code

    2.使用 Lock 实现

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Test14
    {
        private Lock lock = new ReentrantLock(true);
        private Condition condition = lock.newCondition();
    
        public void printNum() throws InterruptedException
        {
    
            try
            {
                System.out.println("num 运行了");
    //            if (true)
                if (lock.tryLock(1, TimeUnit.SECONDS))
                {
                    System.out.println("num 获得锁了");
    //                lock.lock();
                    for (int i = 1; i <= 52; i++)
                    {
                        System.out.print(i + ",");
                        if (i % 2 == 0)
                        {
                            try
                            {
                                condition.signal();
                                if (i != 52)
                                {
                                    condition.await();
                                }
                            }
                            catch (InterruptedException e)
                            {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                lock.unlock();
            }
        }
    
        public void printLetter()
        {
            try
            {
                System.out.println("Letter 运行了");
    //            if (true)
                if (lock.tryLock(1, TimeUnit.SECONDS))
                {
                    System.out.println("Letter 获得锁了");
    //                lock.lock();
                    for (int i = 0; i < 26; i++)
                    {
                        try
                        {
                            System.out.println((char) ('A' + i));
                            condition.signal();
                            if (i != 25)
                            {
                                condition.await();
                            }
                        }
                        catch (InterruptedException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                lock.unlock();
            }
        }
    }

      结果 :

    Letter 运行了
    num 运行了
    Letter 获得锁了
    A
    num 获得锁了
    1,2,B
    3,4,C
    5,6,D
    7,8,E
    9,10,F
    11,12,G
    13,14,H
    15,16,I
    17,18,J
    19,20,K
    21,22,L
    23,24,M
    25,26,N
    27,28,O
    29,30,P
    31,32,Q
    33,34,R
    35,36,S
    37,38,T
    39,40,U
    41,42,V
    43,44,W
    45,46,X
    47,48,Y
    49,50,Z
    51,52,
    View Code

    明明是先 t1.start(); 但是这里先运行,先得到锁的却是t2. 这里用的是公平锁  Lock lock = new ReentrantLock(true); 保证先申请的线程先获得锁. 这说明线程的运行顺序是由JVM随机分配的,并不是我们代码中先开启就先运行.

    二、解读:

    1. synchronized  底层使用的也是 reentrantLock ,默认是非公平锁(先申请锁的线程不一定先获得锁),synchronized  使用的线程间的通信机制用的是 wait/notify ,在使用 notify() 或者 notifyAll() 进行通知时,被通知的线程或者顺序是由JVM随机选择的.

    2. reentrantLock 默认非公平锁,线程间使用 condition 进行通信.利用 Condition 可以实现 "选择性通知" ,condition.await() 进行阻塞;  condition.signal(); 进行唤醒

    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();

     如上所示,同一个lock 可以产生多个 condition对象.可以用不同的 comdition对象去操作不同的线程.

    问题:

    在上面的运用场景中当使用 synchronized  时每次都是t1线程先运行,先获得锁.但是使用 lock的 trylock方法时,运行却是相当的不确定,有时是t1先运行,先获得锁,有时是t2. 但是不使用trylock方法而改使用lock.lock()方法时,试了很多次,跟 使用 synchronized  时是一样的.前面有提到线程的运行顺序是JVM随机分配的,在这里似乎又难以解释这种现象.谜!

    public class Test15 extends Thread
    {
        @Override
        public void run()
        {
            super.run();
            System.out.println(Thread.currentThread().getName() + ": 运行了");
        }
    }
    public class Test16
    {
        public static void main(String[] args)
        {
            Thread[] arr = new Thread[10];
            
            for (int i = 0; i < arr.length; i++)
            {
                arr[i] = new Test15();
                arr[i].setName("线程: " + i);
            }
            
            for (int i = 0; i < arr.length; i++)
            {
                arr[i].start();
            }
        }
    }

     结果:

    线程: 0: 运行了
    线程: 1: 运行了
    线程: 4: 运行了
    线程: 2: 运行了
    线程: 3: 运行了
    线程: 6: 运行了
    线程: 8: 运行了
    线程: 7: 运行了
    线程: 5: 运行了
    线程: 9: 运行了
    View Code

     顺序开启10个线程,但是线程的运行顺序和开启顺序是不一致的. 

  • 相关阅读:
    WIN32窗口框架代码,完善了菜单和子窗口,纯API,可自由扩展,C语言也可以写桌面程序
    自制WINDOWS窗口框架(修改完善后实现了输入和显示功能),C+WIN-API,再也不用面对黑框框学C语言了
    定义一个判断素数的函数
    定义一元二次方程求根函数
    定义一个二维数组反置函数
    让C语言告别简陋的黑框框,WIN32窗口显示九九乘法表(纯C代码)
    C语言练习题40——将一个数组逆序输出
    c语言练习39——向数列中插入一个数
    c语言练习38——求3*3矩阵对角线之和
    js之好看的鼠标点击-光标特效
  • 原文地址:https://www.cnblogs.com/hoonick/p/10790673.html
Copyright © 2011-2022 走看看