java线程同步 synchronized同步锁

来源:互联网 发布:python 定时任务 编辑:程序博客网 时间:2024/05/19 20:45

“非线程安全”是多个线程对同一个对象中的实例变量进行并发访问时发生的,而“线程安全”就是获得的实例变量的值是经过同步处理,不会出现脏读现象。

方法内的变量为线程安全

“非线程安全”问题存在于“实例变量中”,如果是方法内部的私有变量,则不存在“非线程安全”问题。如:

//测试程序public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton() {}public static final Singleton getInstance() {return SingletonHolder.INSTANCE;}public void service() throws InterruptedException {int i = 0;//方法内部变量while (i < 10) {Thread.sleep(500); System.out.println(++i);}}}//调用线程public class Thread1 implements Runnable {private Singleton service = null;public Thread1(Singleton service) {this.service = service;}@Overridepublic void run() {try {service.service();} catch (InterruptedException e) {}}}//执行3个同样的线程public class Main {public static void main(String[] args) {Singleton service = Singleton.getInstance();Thread1 t1 = new Thread1(service);new Thread(t1).start();Thread2 t2 = new Thread2(service);new Thread(t2).start();Thread3 t3 = new Thread3(service);new Thread(t3).start();}}//运行结果000111222……

方法内部的变量是私有的,每个线程保存一份变量值,不会存在非线程安全问题。

//将 i 改为实例变量public class Singleton {private int i = 0;//成员变量private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton() {}public static final Singleton getInstance() {return SingletonHolder.INSTANCE;}public void service() throws InterruptedException {while (i < 10) {Thread.sleep(500);System.out.println(++i);}}}//运行结果11234567891011

线程交叉运行,得到的结果不符合期望结果。使用synchronized关键字可以通过修饰方法和代码块的方式进行线程间的同步。多个线程间试图访问同一个对象监视器将会被阻塞。程序退出同步方法或者代码块后释放锁。

//在service方法中用synchronized修饰代码块public void service() throws InterruptedException {    synchronized(this){        while (i < 10) {             Thread.sleep(500);             System.out.println(++i); }}}//运行结果12345678910
this对象监视器
使用synchronized修饰方法时,对象监视器使用的是对象本身作为监视器对象,就是this,与synchronized(this)为同一个对象监视器

public class Service {public synchronized void methodA() throws InterruptedException {//同步方法Afor (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodA");}}public synchronized void methodB() throws InterruptedException {//同步方法Bfor (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodB");}}public void methodC() throws InterruptedException {synchronized (this) {//同步代码块Cfor (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodC");}}}public static void main(String[] args) {Service service = new Service();Thread1 t1 = new Thread1(service);//线程1调用方法methodAnew Thread(t1).start();Thread2 t2 = new Thread2(service);//线程2调用方法methodBnew Thread(t2).start();Thread3 t3 = new Thread3(service);//线程3调用方法methodCnew Thread(t3).start();}}执行结果:methodAmethodAmethodAmethodCmethodCmethodCmethodBmethodBmethodB

3个线程的对象监视器都为service对象,3个线程间互斥运行,不同对象间不会互斥:

public static void main(String[] args) {//创建3个不同的对象Thread1 t1 = new Thread1(new Service());new Thread(t1).start();Thread2 t2 = new Thread2(new Service());new Thread(t2).start();Thread3 t3 = new Thread3(new Service());new Thread(t3).start();}执行结果:methodAmethodBmethodCmethodAmethodBmethodCmethodAmethodBmethodC

Object对象监视器

synchronized可以指定一个对象来作为对象监视器,Object对象监视器通过synchronized(Object)修饰代码块获取锁,与试图获取同一Object对象锁的代码互斥。

public class OtherService {private Object obj = null;public OtherService(Object obj) {this.obj = obj;}public void methodC() throws InterruptedException {synchronized (obj) {//使用object对象监视器for (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodC");}}}}public class Service {public synchronized void methodA() throws InterruptedException {//同步方法for (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodA");}}public void methodB() throws InterruptedException {synchronized (this) {//同步代码块for (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodB");}}}public static void main(String[] args) {Service service = new Service();//service作为同步对象Thread1 t1 = new Thread1(service);//调用methodA方法new Thread(t1).start();Thread2 t2 = new Thread2(service);//调用methodB方法new Thread(t2).start();Thread3 t3 = new Thread3(new OtherService(service));调用methodC方法new Thread(t3).start();}}执行结果:methodAmethodAmethodAmethodCmethodCmethodCmethodBmethodBmethodB

ServicemethodAmethodB获取的都是this的对象监视器。将service对象传给了OtherServiceOtherService的对象监视器与servicethis为同一对象,代码互斥运行。

class类对象监视器

synchronized修饰static方法时,获取的对象监视器为class的对象,与其它试图获取相同class类型的锁互斥。

public class Service {public synchronized static void methodA() throws InterruptedException {//synchronized修饰的静态方法for (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodA");}}public void methodB() throws InterruptedException {synchronized (Service.class) {//使用class类型对象监视器for (int i = 0; i < 3; i++) {Thread.sleep(2000);System.out.println("methodB");}}}public static void main(String[] args) {Service service = new Service();Thread1 t1 = new Thread1(service);//线程1调用methodAnew Thread(t1).start();Thread2 t2 = new Thread2(service);//线程2调用methodBnew Thread(t2).start();}}执行结果:methodAmethodAmethodAmethodBmethodBmethodB

代码之间互斥运行。class对象监视器与Object对象监视器不会相互影响

public class Service {private int i = 0;public synchronized void service() throws InterruptedException {//普通synchronized方法while (i < 5) {Thread.sleep(500);System.out.println("service1:"+ ++i);}}public void service2() throws InterruptedException {synchronized (Service.class) {//class对象监视器代码块while (i < 5) {Thread.sleep(500);System.out.println("service2:"+ ++i);}}}}public class Main {public static void main(String[] args) {Service service = new Service();Thread1 t1 = new Thread1(service);//调用service1()new Thread(t1).start();Thread2 t2 = new Thread2(service);//调用service2()new Thread(t2).start();}}//运行结果service1:1service2:1service2:2service1:3service1:4service2:4service1:5service2:6

线程出现了交叉运行

synchronized锁重入

当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象锁的。有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话就会造成死锁。就是在同步的代码中依然可以调用请求同一个对象锁的代码不会出现阻塞。

public class Service {public synchronized void service() throws InterruptedException {System.out.println("service1");service2();}public void service2() throws InterruptedException {synchronized (this) {service3();System.out.println("service2");}}public synchronized void service3() throws InterruptedException {System.out.println("service3");}}//运行结果service1service3service2

 
原创粉丝点击