sysynchronized关键字能够修饰方法、代码块,但不能修饰构造器、成员变量等。java
当sysynchronized关键字同来修饰方法和代码块时,可以保证同一时刻最多只有一个线程执行该段代码或方法。防止当有两个线程并发修改同一个文件时可能会形成异常。编程
同步代码块语法:安全
synchronized(obj){
...
//此处代码是同步代码块
}
复制代码
意思为:当线程要执行如下代码块以前,必须先得到对obj的锁。bash
然而,另外一个当一个线程访问object的一个synchronized(this)代码块时,另外一个线程仍然能够访问该object中的非synchronized(this)同步代码块,可是其余线程对object中其余全部的synchronized(this)同步代码块的访问将被阻塞。并发
示例:ide
public class Thread1 {
public void synchronize() {
synchronized (this) {
System.out.println("I am the synchronized part:");
for (int i=0; i<3; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("the synchronized part is over");
}
}
public void synchronize2() {
synchronized (this) {
System.out.println("I am the synchronized part 2:");
for (int i=0; i<3; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("the synchronized part 2 is over");
}
}
public void nonSynchronize() {
System.out.println("non-synchronized part:");
for (int i=0; i<3; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("the non-synchronized part is over");
}
public static void main(String[] args) {
final Thread1 thread1 = new Thread1();
//启动线程,线程一、2和3分别用了不一样的表达式
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
thread1.synchronize();
}
});
Thread t2 = new Thread(() -> thread1.synchronize2());
Thread t3 = new Thread(thread1::nonSynchronize);
t1.start();
t2.start();
t3.start();
}
}复制代码
输出结果:工具
从输出结果能够看出:线程0执行的是第一个同步代码块,线程2执行的是非同步代码块,线程0和2同时执行,二者互不干扰。线程1执行的是第二个同步代码块,由于线程0先得到对该对象的锁定,因此线程1即便执行代码块跟线程0不同,也被阻塞,必须等线程1执行完同步代码块,释放锁,线程1才能继续执行。this
public class Thread1 {
private synchronized void synchronize() {
System.out.println("I am the synchronized method part:");
for (int i=0; i<3; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("the synchronized method part is over");
}
private synchronized void synchronize2() {
System.out.println("I am the synchronized method part 2:");
for (int i=0; i<3; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("the synchronized method part 2 is over");
}
private void nonSynchronize() {
System.out.println("non-synchronized method part:");
for (int i=0; i<3; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("the non-synchronized method part is over");
}
public static void main(String[] args) {
final Thread1 thread1 = new Thread1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
thread1.synchronize();
}
});
Thread t2 = new Thread(() -> thread1.synchronize2());
Thread t3 = new Thread(thread1::nonSynchronize);
t1.start();
t2.start();
t3.start();
}
}复制代码
输出结果跟同步代码块同样:spa
Lock 是控制多个线程对共享资源进行访问的工具。每次只能有一个线程对Lock对象加锁,线程开始访问共享资源以前应先得到Lock对象。.net
在实现线程安全的控制中,比较经常使用的是ReentrantLock。
class X {
private final ReentrantLock lock = new ReentrantLock();
//定义须要保证线程安全的方法
public void m() {
//加锁
lock.lock();
try {
//method body
} finally { //使用finally来保证释放锁
lock.unlock();
}
}
}复制代码
参考资料:java加锁与同步方法
疯狂java讲义(第三版)
Java编程思想(第4版)