zoukankan      html  css  js  c++  java
  • Java提高——多线程(三)同步、锁

    线程同步

    线程的同步是为了防止多个线程访问同一个数据对象时,对数据造成破坏。

    同步的方法就是使用synchronized关键字。

    每个对象有且仅有一个同步锁,意味着同步锁依赖于对象而存在。每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法时,自动获得与当前执行的代码类的当前实例(this)有关的锁。当程序运行到synchronized方法时,就获得了该对象的同步锁。不同线程对同步锁是互斥的

    synchronized(obj){、、、、、}——>获得了obj对象的同步锁。

    synchronized可以修饰方法和代码块,但是不能修饰构造器、成员变量等。

    synchronized的规则:

    —>当一个线程访问一个synchronized方法或代码块时,其他线程对该对象访问将被阻塞。

    —>当一个线程访问一个synchronized方法或代码块时,其他线程可以访问该对象的非同步代码块

    —>当一个线程访问一个synchronized方法或代码块时,其他线程对该对象的其他synchronized方法或代码块将被阻塞。

    1、

    public class SynchronizedTest {
        public static void main(String[] args) {
            Runnable demo = new demo1();
    
            Thread t1 = new Thread(demo,"t1");
            Thread t2 = new Thread(demo,"t2");
            t1.start();
            t2.start();
        }
        static class demo1 implements Runnable{
            @Override
            public void run(){
                synchronized (this){
                    for (int i = 0; i < 10; i++) {
                        System.out.print(Thread.currentThread().getName()+"-"+i+" ");
                    }
                }
            }
        }
    }
    

    2、

    public class SynchronizedTest {
        public static void main(String[] args) {
            final demo1 demo = new demo1();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.ru();
                }
            }, "t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.go();
                }
            }, "t2");
            t1.start();
            t2.start();
        }
    }
     class demo1{
        public void ru(){
            synchronized (this){
                for (int i = 0; i < 10; i++) {
                    System.out.print(Thread.currentThread().getName()+"-"+i+" ");
                }
            }
        }
        public void go(){
            System.out.println("非同步方法");
        }
    }
    

    3、

    public class SynchronizedTest {
        public static void main(String[] args) {
            final demo1 demo = new demo1();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.ru();
                }
            }, "t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.go();
                }
            }, "t2");
            t1.start();
            t2.start();
        }
    }
     class demo1{
        public void ru(){
            synchronized (this){
                for (int i = 0; i < 10; i++) {
                    System.out.print(Thread.currentThread().getName()+"-"+i+" ");
                }
            }
        }
        public void go(){
            synchronized (this) {
                System.out.println("非");
                for (int i = 0; i < 10; i++) {
                    System.out.print(Thread.currentThread().getName()+"-"+i+" ");
                }
            }
        }
    }
    
    同步锁(Lock)

    lock是控制多个线程对共享资源进行访问的工具。提供了对共享资源的独占访问,线程访问共享资源之前要先获得Lock对象 ,每次只能有一个对象对Lock对象枷锁

    实现线程控制中比较常用的是ReentrantLock(可重入锁),使用该锁可以显示的加锁、释放锁

    class ruo{
        //获取锁对象
        private final ReentrantLock loc = new ReentrantLock();
        //......
        public void re(){
            //加锁
            loc.lock();
            try{
                //需要保证线程安全的代码
                //.....
            }finally {
                //释放锁
                loc.unlock();
            }
        }
    }

    使用Lock与同步方法有点类似,只是Lock是显示的使用Lock对象作为同步锁,而使用同步方法是系统隐式的使用当前对象作为同步监视器。

    ReentantLock具有可重入性,就是一个线程可以对已被加锁的ReentrantLock锁再次加锁。

    死锁

    当两个线程相互等待对方释放同步监视器的时候就会发生死锁。一旦发生死锁,程序不会发生任何异常也不会有任何提示,只是所有线程被阻塞,无法继续。

    class A{
        public synchronized void foo(B b){
            System.out.println("foo方法");
            b.last();
        }
        public synchronized void last(){
            System.out.println("a.last");
        }
    }
    class B{
        public synchronized void bar(A a){
            System.out.println("bar方法");
            a.last();
        }
        public synchronized void last(){
            System.out.println("b.last");
        }
    }
    public class DeadLock implements Runnable{
        A a = new A();
        B b = new B();
        public void init(){
            Thread.currentThread().setName("主线程");
            a.foo(b);
        }
        @Override
        public void run() {
            Thread.currentThread().setName("副线程");
            b.bar(a);
        }
        public static void main(String[] args) {
            DeadLock deadLock = new DeadLock();
            //以deadLock为target启动新的线程
            new Thread(deadLock).start();
            //调用init()方法
            deadLock.init();
        }
    }
    

    程序发生死锁,没提醒,无异常




  • 相关阅读:
    【Java基础】浅谈常见设计模式
    面试中的排序算法总结
    Spring Boot中静态资源(JS, 图片)等应该放在什么位置
    分布式缓存技术redis学习系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
    分布式缓存技术redis学习系列(三)——redis高级应用(主从、事务与锁、持久化)
    分布式缓存技术redis学习系列(二)——详细讲解redis数据结构(内存模型)以及常用命令
    Springmvc参数绑定
    SpringMVC框架的图片上传
    全文检索技术ElasticSearch
    MQ(Message Queue)消息队列
  • 原文地址:https://www.cnblogs.com/huangzhe1515023110/p/9276095.html
Copyright © 2011-2022 走看看