synchronized锁和Lock锁

synchronized

对象锁-使用方式1

public class Demo2 {
    public static void main(String[] args) {

        Demo2 demo = new Demo2();
        Thread t1 = new Thread(()->{
            demo.a();
        });

        Thread t2 = new Thread(()->{
            demo.b();
        });

        t1.start();
        t2.start();
    }

    public synchronized void a() {
        try {
            System.out.println("aaaaaaaaaa");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public synchronized void b() {
        try {
            System.out.println("bbbbbbbbbbbbbbbb");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
View Code

上边代码示例中t1和t2两个线程使用同一个Demo2对象分别调用a,b两个方法。两个线程的执行是串行的。因为synchronized在方法上则默认使用当前对象锁。

public class Demo2 {
    public static void main(String[] args) {


        Thread t1 = new Thread(()->{
            Demo2 demo = new Demo2();
            demo.a();
        });

        Thread t2 = new Thread(()->{
            Demo2 demo = new Demo2();
            demo.b();
        });

        t1.start();
        t2.start();
    }

    public synchronized void a() {
        try {
            System.out.println("aaaaaaaaaa");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public synchronized void b() {
        try {
            System.out.println("bbbbbbbbbbbbbbbb");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
View Code

在每个线程内创建自己的Demo2对象,两个线程则是并行的。

对象锁-使用方式2

public class Demo2 {
    public static void main(String[] args) {

        Object lock = new Object();

        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.b(lock);
        });

        t1.start();
        t2.start();
    }

    public void a(Object lock) {
        synchronized (lock) {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void b(Object lock) {
        synchronized (lock) {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
View Code

将synchronized转移到方法内部,组成一个同步代码块,同步代码块接收一个对象类型的参数。在main中创建了一个Object对象,将这个对象分别传递给两个线程的a,b方法。执行结果是串行的,因为两个线程使用的是同一个对象,即同一个锁。

public class Demo2 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            Demo2 demo = new Demo2();
            demo.a();
        });

        Thread t2 = new Thread(() -> {
            Demo2 demo = new Demo2();
            demo.b();
        });

        t1.start();
        t2.start();
    }

    public void a() {
        synchronized (this) {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void b() {
        synchronized (this) {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
View Code

将代码稍稍修改,每个线程都使用自己的Demo2对象,而同步代码块中写this,这表示每个线程的锁都是自己的Demo2对象,所以结果是并行执行。同步代码块中的对象可以是任意对象,但是使用同一个对象的方法必然会互斥。

类锁-使用方式1

public class Demo2 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            Demo2.a();
        });

        Thread t2 = new Thread(() -> {
            Demo2.b();
        });

        t1.start();
        t2.start();
    }

    public synchronized static void a() {
        try {
            System.out.println("aaaaaaaaaa");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public synchronized static void b() {
        try {
            System.out.println("bbbbbbbbbbbbbbbb");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
View Code

在static方法上使用synchronizedz则表示synchronized使用的是当前类对象。以上代码是串行执行的。

类锁-使用方式2

public class Demo2 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            Demo2.a();
        });

        Thread t2 = new Thread(() -> {
            Demo2.b();
        });

        t1.start();
        t2.start();
    }

    public static void a() {
        synchronized (Demo2.class) {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void b() {
        synchronized (Demo2.class) {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
View Code

在static方法内部使用synchronized代码块,代码块中只能接收类对象,以上代码传的是同一个类对象Demo2.class。所以执行结果是串行的。

public class Demo2 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            Demo2.a();
        });

        Thread t2 = new Thread(() -> {
            Demo2.b();
        });

        t1.start();
        t2.start();
    }

    public static void a() {
        synchronized (Demo2.class) {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void b() {
        synchronized (Object.class) {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
View Code

将代码修改为a和b分别持有Demo2.class和Object.class执行结果是并行的。这种写法可以接收任意的class。

Lock锁

在JDK5有了java.util.concurrent包,也就是大家说的JUC,Lock接口在JUC的子包java.util.concurrent.locks中。ReentrantLock是其中的一个实现。

lock()-unlock()

public class Test1 {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();

        Test1 test1 = new Test1();
        Thread t1 = new Thread(() -> {
            test1.a(lock);
        });

        Thread t2 = new Thread(() -> {
            test1.b(lock);
        });

        t1.start();
        t2.start();
    }

    public void a(Lock lock) {
        try {
            lock.lock();
            System.out.println("aaaaaaaaaa");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void b(Lock lock) {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbbbb");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}
View Code

a,b两个方法使用的是同一个ReentrantLock对象,只有同一个lock才能有锁的效果,以上代码是串行执行的。lock()加锁,unlock()解锁。它们是同一组操作。

public class Test1 {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();
        ReentrantLock lock2 = new ReentrantLock();

        Test1 test1 = new Test1();
        Thread t1 = new Thread(() -> {
            test1.a(lock);
        });

        Thread t2 = new Thread(() -> {
            test1.b(lock2);
        });

        t1.start();
        t2.start();
    }

    public void a(Lock lock) {
        try {
            lock.lock();
            System.out.println("aaaaaaaaaa");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void b(Lock lock) {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbbbb");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}
View Code

如果在增加一个ReentrantLock对象,a,b两个方法使用的不是同一个,运行结果就是并行的。

tryLock()

public class Test2 {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();

        Test2 test1 = new Test2();
        Thread t1 = new Thread(() -> {
            test1.a(lock);
        });

        Thread t2 = new Thread(() -> {
            test1.b(lock);
        });

        t1.start();
        t2.start();
    }

    public void a(Lock lock) {
        boolean b = lock.tryLock();
        if (b) {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("获取锁失败");
        }
    }

    public void b(Lock lock) {
        boolean b = lock.tryLock();
        if (b) {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("获取锁失败");
        }

    }
}
View Code

如果一个线程通过tryLock获取锁失败则会返回false,返回true则表示拿到了锁。

tryLock(long time, TimeUnit unit)

public class Test3 {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();

        Test3 test1 = new Test3();
        Thread t1 = new Thread(() -> {
            test1.a(lock);
        });

        Thread t2 = new Thread(() -> {
            test1.b(lock);
        });

        t1.start();
        t2.start();
    }

    public void a(Lock lock) {
        boolean b = false;
        try {
            b = lock.tryLock(2, TimeUnit.SECONDS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        if (b) {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("获取锁失败");
        }
    }

    public void b(Lock lock) {
        boolean b = false;
        try {
            b = lock.tryLock(2, TimeUnit.SECONDS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        if (b) {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("获取锁失败");
        }

    }
}
View Code

在设定的time时间内如果还是没有获取到锁,才返回false。

lockInterruptibly()

public class Test4 {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();

        Test4 test1 = new Test4();
        Thread t1 = new Thread(() -> {
            test1.a(lock);
        });

        Thread t2 = new Thread(() -> {
            test1.b(lock);
        });

        t1.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
        }
        t2.start();

      /* t1.interrupt();执行结果
       aaaaaaaaaa
        Exception in thread "Thread-0" java.lang.RuntimeException: aaaaaaaaaaaaaaaa打断施法java.lang.InterruptedException: sleep interrupted
        at com.dfsn.cloud.consumer.locks.Test4.a(Test4.java:51)
        at com.dfsn.cloud.consumer.locks.Test4.lambda$main$0(Test4.java:15)
        at java.lang.Thread.run(Thread.java:748)
        bbbbbbbbb*/
        //   t1.interrupt();

  /*    t2.interrupt();的执行结果
        aaaaaaaaaa
        Exception in thread "Thread-1" java.lang.RuntimeException: bbbbbbbbbbbb打断施法java.lang.InterruptedException
        at com.dfsn.cloud.consumer.locks.Test4.b(Test4.java:52)
        at com.dfsn.cloud.consumer.locks.Test4.lambda$main$1(Test4.java:19)
        at java.lang.Thread.run(Thread.java:748)*/
        // t2.interrupt();
    }

    public void a(Lock lock) {
        try {
            lock.lockInterruptibly();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        try {
            System.out.println("aaaaaaaaaa");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException("aaaaaaaaaaaaaaaa打断施法" + e);
        } finally {
            lock.unlock();
        }
    }

    public void b(Lock lock) {
        try {
            lock.lockInterruptibly();
        } catch (Exception e) {
            throw new RuntimeException("bbbbbbbbbbbb打断施法" + e);
        }

        try {
            System.out.println("bbbbbbbbb");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}
View Code

这个方法牵扯到Thread类中的interrupted()方法。对启动的线程使用interrupted方法,则该线程会接收到一个中断的信号,该信号不会停止线程的运行,但如果线程内有调用wait,join,sleep等方法,则会收到一InterruptedException异常。

使用lockInterruptibly()获取锁,然后调用线程的interrupted()如果当前线程已经获取到了锁正在运行中,线程则会接收一个中断信号量,如上所说。但如果当前线程没有获取到锁,处于等待状态,则lockInterruptibly()也会抛出一个InterruptedException。

公平锁和非公平锁

public class Demo5 {

    private Lock lock = new ReentrantLock(false);    //如果不传递等于传递false,可以传递true表示公平锁

    public static void main(String[] args) throws InterruptedException {
        final Demo5 test = new Demo5();

        test.lock.lock();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t1.start();


        Thread t2 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t2.start();


        Thread t3 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t3.start();


        Thread t4 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t4.start();


        Thread t5 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t5.start();


        Thread t6 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t6.start();


       test.lock.unlock();

    }
View Code

创建ReentrantLock时如果不传递参数则默认是false非公平锁。如果是公平锁得情况下会根据线程的等待顺序分配锁,而非公平锁则是随机分配。

ReentrantLock的其他方法

public class Demo6 extends ReentrantLock{

    public static void main(String[] args) throws InterruptedException {

        final Demo6 test = new Demo6();

        test.lock();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t1.start();


        Thread t2 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t2.start();


        Thread t3 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t3.start();


        Thread t4 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t4.start();


        Thread t5 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t5.start();


        Thread t6 = new Thread() {
            @Override
            public void run() {
                test.insert(Thread.currentThread());
            }
        };
        t6.start();

        System.out.println("查询此锁是否由当前线程持有。"+test.isLocked());
        System.out.println("查询此锁是否由任何线程持有。"+test.isLocked());
        System.out.println("如果此锁的公平设置为true,则返回 true 。"+test.isFair());
        System.out.println("查询是否有线程正在等待获取此锁。"+test.hasQueuedThreads());
        System.out.println("查询给定线程是否等待获取此锁。"+test.hasQueuedThread(t1));
        System.out.println("返回等待获取此锁的线程数的估计。"+test.getQueueLength());
        System.out.println("返回当前拥有此锁的线程,如果不拥有,则返回 null 。"+test.getOwner().getName());
        System.out.println("查询当前线程对此锁的暂停数量。"+test.getHoldCount());
        System.out.println("返回包含可能正在等待获取此锁的线程的集合。"+test.getQueuedThreads().size());
        test.unlock();
        System.out.println("查询此锁是否由当前线程持有。"+test.isLocked());
        Thread.sleep(2000);
        System.out.println("查询是否有线程正在等待获取此锁。"+test.hasQueuedThreads());
        System.out.println("查询给定线程是否等待获取此锁。"+test.hasQueuedThread(t1));
        System.out.println("返回等待获取此锁的线程数的估计。"+test.getQueueLength());
        System.out.println("返回当前拥有此锁的线程,如果不拥有,则返回 null 。"+test.getOwner());
        System.out.println("查询当前线程对此锁的暂停数量。"+test.getHoldCount());
        System.out.println("返回包含可能正在等待获取此锁的线程的集合。"+test.getQueuedThreads().size());
    }


    public void insert(Thread thread) {
        lock();
        try {
            System.out.println(thread.getName() + "得到了锁");
            Thread.sleep(1000);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            System.out.println(thread.getName() + "释放了锁");
            unlock();
        }
    }
}
View Code

 

 

 

 

 

 

 

posted @ 2021-01-13 17:06  顶风少年  阅读(205)  评论(0编辑  收藏  举报
返回顶部