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:\t" + 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:\t" + 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对象去操作不同的线程.

猜你喜欢

转载自www.cnblogs.com/hoonick/p/10790673.html