Java 中Synchronized的用法

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

一,对象锁
修饰一个代码块
1.一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。我们看下面一个例子:
【Demo1】:synchronized的用法

 1 /**
 2 * 同步线程
 3 */
 4 class SyncThread implements Runnable {
 5         private static int count;
 6 
 7         public SyncThread() {
 8             count = 0;
 9         }
10 
11         public void run() {
12             synchronized(this) {
13                 for (int i = 0; i < 5; i++) {
14                     try {
15                         System.out.println(Thread.currentThread().getName() + ":" + (count++));
16                         Thread.sleep(100);
17                     } catch (InterruptedException e) {
18                         e.printStackTrace();
19                     }
20                 }
21             }
22         }
23 
24         public int getCount() {
25             return count;
26         }
27 }

SyncThread的调用:

 SyncThread syncThread = new SyncThread();
 Thread thread1 = new Thread(syncThread, "SyncThread1");
 Thread thread2 = new Thread(syncThread, "SyncThread2");
 thread1.start();
 thread2.start();

结果如下:

复制代码
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9

案例二:

public class SynchronizedExample1 {
private final int loopNum = 20; // 修饰一个代码块 private void test1(int j) { synchronized (this) {
for (int i = 0; i < loopNum; i++) {
  log.info("test1 {} - {}", j, i);
}
}
}

// 修饰一个方法 private synchronized void test2(int num) {
for (int i = 0; i < loopNum; i++) {
   log.info("test2 {} - {}", num, i);
}
}

public static void main(String[] args) { SynchronizedExample1 example1 = new SynchronizedExample1(); SynchronizedExample1 example2 = new SynchronizedExample1(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> {
example1.test2(1);
});
executorService.execute(() -> {
example2.test2(2);
});
executorService.shutdown();
}
}

1.1 代码块修饰(对象)
此时,synchronized用于保证test1函数中的被synchronized大括号包裹的代码同步执行.synchronized作用的对象为SynchronizedExample1的对象实例,例如main函数中的example1以及example2.

Tips:
example1若在多个线程中被调用,其输出顺序将保证同步,按照1,2,3…19,20的顺序执行.2.若example1与example2均在多个线程中执行,则test1…之间保持同步输出,test2…之间保持同步输出,但test1…与test2…之间输出不保证顺序.

二. 类锁

public class SynchronizedExample2 {
private static final int loopNum = 20; // 修饰一个类 private static void test1(int j) { 
synchronized (SynchronizedExample2.class) {
 for (int i = 0; i < loopNum; i++) { 
    log.info("test1 {} - {}", j, i); } } } // 修饰一个静态方法 private static synchronized void test2(int j) {
     for (int i = 0; i < loopNum; i++) { log.info("test2 {} - {}", j, i); } }
public static void main(String[] args) { SynchronizedExample2 example1 = new SynchronizedExample2(); SynchronizedExample2 example2 = new SynchronizedExample2(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> { example1.test1(1); }); executorService.execute(() -> { example2.test1(2); }); }}

2.1 代码块修饰(类)
与1.1中区别在于,synchronized函数修饰的是SynchronizedExample2类.
SynchronizedExample2对象,诸如example1或者example2在任意多的线程中调用test1函数,其输出顺序均会被保证(1,2,3,4…19,20).

三 .Lock(锁)

        Lock lock = new ReentrantLock();    //注意这个地方
        lock.lock();
        try {
            System.out.println(thread.getName()+"得到了锁");
            for(int i=0;i<5;i++) {
                arrayList.add(i);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }finally {
            System.out.println(thread.getName()+"释放了锁");
            lock.unlock();
        }
发布了262 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/baidu_41666295/article/details/103964397