0、有关多线程的实现先参考:Java基础之多线程的基本实现
1、两个线程访问同一个对象,如果没有同步的限制,会出现一个意想不同的问题;
2、比如对象成员属性int i = 100;某方法每执行一次都会对该值进行减1操作,直接为0结束;
3、单次调用的基本流程应该是:start->{body}->end;但从start到end这个过程是需要时间的;
4、假设是完整过程是A->B->C,如果两个线程同时执行则会出现A调用还未结束B即开始调用;
5、理想的过程是A1->B1->C1->A2->B2->C2->A3->B3->C3,两个线程一起来则会出现A1->A2->B1->C1->B2->C2;
6、为了保证A->B->C这三步能不被中断,完整地一个一个执行,则需要对A->B->C进行加锁保护;
7、加锁保护即使之同步,使开始A就到C之后再重新开启一个新过程;
8、代码块需要加锁则使用修饰词synchronized(){}将代码包含在大括号内;
9、整个方法需要加锁则在方法修饰词中加synchronized关键字
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class Demo{ public static void main(String [] args){ // 创建一个Service对象,使两个线程同时对该对象进行操作 Service service = new Service(); // 线程1访问Service对象的第一个方法,因为同步方法,service对象会被锁定 Thread thread1 = new Thread(new Runnable(){ public void run(){ service.fun1(); } }); // 线程2访问Service对象的第二个方法 // 由于第二个方法包含synchronized修饰 // 并且同步加锁的是service对象本身; // 所以线程2只能等待service解锁后才能执行 Thread thread2 = new Thread(new Runnable(){ public void run(){ service.fun2(); } }); thread1.start(); thread2.start(); } } // 同步方法的两种写法 class Service{ // 1、在方法修饰词前加synchronized public synchronized void fun1(){ try{ Thread.sleep(3000); }catch(Exception e){ System.out.println(e); } System.out.println("fun1"); } // 2、在代码块中加synchronized(){}来修饰 public void fun2(){ synchronized(this){ System.out.println("fun2"); } } } |
运行结果:
fun1
fun2
说明线程2在等待线程1结束后才执行,如果将方法fun2里的synchronized修饰词去掉则线程2会先执行完!