Java线程同步

线程同步:线程同步是为了解决线程安全问题。

     有三种方式完成同步操作:

  1. 同步代码块。
  2. 同步方法。
  3. 锁机制(Lock锁)。

问题引入:

窗口1线程进入操作的时候,窗口2和窗口3线程只能在外等着,窗口1操作结束,窗口1和窗口2和窗口3才有机会进入代码去执行。也就是说在某个线程修改共享资源的时候,其他线程不能修改该资源,等待修改完毕同步之后,才能去抢夺CPU资源,完成对应的操作,保证了数据的同步性,解决了线程不安全的现象。

方式一:同步代码块

 synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

格式:

synchronized(对象锁){

     需要同步操作的代码

}

 语法:synchronized(对象锁){ 代码块}

 对象锁: 任何一个对象都是可以作为对象锁,包括类

 *      1.this       who调用当前方法,who就是对象锁   搭配成员方法进行使用

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *          通过不同的s1 s2来调用的(不同的锁),出现 争抢 现象

 *

 *      2.类.class   类锁 ,无论创建多少个对象,类锁都是同一把  搭配静态方法进行使用

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *          通过不同的s1 s2来调用的(不同的锁),出现 有序等待 现象

 *

 *      3.字符串常量 例如“A”  "B"  在字符串常量池中分配内存  String a = "A" ; String b = "A"  a == b 结果是true

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *          通过不同的s1 s2来调用的(不同的锁),出现 有序等待 现象

 *

 *      4.byte[] lock = new byte[0]  开销最小的锁  一般当作属性使用 作用和this是一致的

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *          通过不同的s1 s2来调用的(不同的锁),出现 争抢 现象

public class SyncDemo1 {

    private byte[] lock = new byte[0];//开销最小的锁
    
    //成员方法

    public void test1(){

        //同步代码块  ==> 给一段代码加锁

        // synchronized (this) {          //this代表的是 s1

        //synchronized (SyncDemo1.class){ //类锁 无论创建多少个SyncDemo1的对象 类锁都是同一把

        //synchronized ("A"){             //字符串变量
   
        synchronized (lock){              //开销最小的锁

            for (int i = 0; i < 10; i++) {

                try {

                    TimeUnit.SECONDS.sleep(1);//线程沉睡不会释放对象锁

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                System.out.println(Thread.currentThread().getName() + ",i=" + i);

            }

        }

    }

    public static void main(String[] args) {

        //同一个锁

        SyncDemo1 s1 = new SyncDemo1();

        SyncDemo1 s2 = new SyncDemo1();

        //开启多线程

        new Thread(()->s1.test1(),"线程1").start();

        new Thread(()->s2.test1(),"线程2").start();

    }

}

 

方式二:同步方法

使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

格式:

public synchronized void method(){

       可能会产生线程安全问题的代码

}

      语法:public synchronized 返回值类型 方法名(){}

 *      1.成员方法

 *          类似于this this作为对象锁   who在调用方法,who就是对象锁

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *          通过不同的s1 s2来调用的(不同的锁),出现 争抢 现象

 *

 *      2.静态方法

 *          类似于类锁  类作为对象锁 无论创建多少个对象,类锁都是同一把

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *          通过不同的s1 s2来调用的(不同的锁),出现 有序等待 现象

public class SyncDemo2 {

    //成员方法

    public synchronized void test1(){

        for (int i = 0; i <10 ; i++) {

            try {

                TimeUnit.SECONDS.sleep(1);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(Thread.currentThread().getName()+",i="+i);

        }

    }



    //静态方法

    public static synchronized void test2(){

        for (int i = 0; i <10 ; i++) {

            try {

                TimeUnit.SECONDS.sleep(1);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(Thread.currentThread().getName()+",i="+i);

        }

    }



    public static void main(String[] args) {

        SyncDemo2 s1 = new SyncDemo2();

        SyncDemo2 s2 = new SyncDemo2();

//        new Thread(()->s1.test1(),"线程1").start();

//        new Thread(()->s2.test1(),"线程2").start();

        new Thread(()->s1.test2(),"线程1").start();

        new Thread(()->s2.test2(),"线程2").start();

    }

}

 

方式三:Lock锁

java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大

Lock锁也称同步锁,加锁与释放锁方法化了,如下:

  • public void lock():加同步锁。
  • public void unlock():释放同步锁。

 *      方法:lock()获取锁  unlock()释放锁

 *

 *      1.作为成员属性  和对象有关

 *          private final Lock lock = new ReentrantLock();

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *  *       通过不同的s1 s2来调用的(不同的锁),出现 争抢 现象

 *

 *      2.作为静态属性 和类有关

 *          private final static Lock lock = new ReentrantLock();

 *          通过同一个s1来调用的(同一把锁),出现 有序等待 现象

 *  *       通过不同的s1 s2来调用的(不同的锁),出现 有序等待 现象

 *

 *      注意:必须在finally中释放锁,确保无论是否有异常产生都可以释放锁,

 *         从而避免出现异常没有释放锁导致其他线程始终获取不到锁 --死锁现象

例:

public class LockDemo {

    //成员属性  和对象有关

    //private final Lock lock = new ReentrantLock();

    //静态属性  和类有关

    private final static Lock lock = new ReentrantLock();

    public void test1(){

        try{

            //获取锁

            lock.lock();

            System.out.println(Thread.currentThread().getName()+"获取到锁");

            for (int i = 0; i < 10 ; i++) {

                System.out.println(Thread.currentThread().getName()+",i="+i);

                Thread.sleep(1000);

            }

        } catch (InterruptedException e) {

            e.printStackTrace();

        } finally {

            //无论是否有异常产生 都要释放锁

            lock.unlock();

            System.out.println(Thread.currentThread().getName()+"释放了锁");

        }

    }

    public void test2(){

        try{

            //获取锁

            lock.lock();

            System.out.println(Thread.currentThread().getName()+"获取到锁");

            for (int i = 0; i < 10 ; i++) {

                System.out.println(Thread.currentThread().getName()+",i="+i);

                Thread.sleep(1000);

            }

        } catch (InterruptedException e) {

            e.printStackTrace();

        } finally {

            //无论是否有异常产生 都要释放锁

            lock.unlock();

            System.out.println(Thread.currentThread().getName()+"释放了锁");

        }

    }


    public static void main(String[] args) {

        LockDemo lock1 = new LockDemo();

        LockDemo lock2 = new LockDemo();

        new Thread(()->lock1.test1(),"线程1").start();

        new Thread(()->lock2.test2(),"线程2").start();

    }

}
  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Teeny-TinyIT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值