在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
- 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
- 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
- 修改一个类,其作用的范围是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();
}