本文共 4513 字,大约阅读时间需要 15 分钟。
在java中要实现多线程之间的同步操作主要有如下两种方式:synchronized关键字和对象的wait()和notify()/notifyAll();
首先来看一下synchronized关键的字的使用
作用范围:
package com.ziwu.learn.thread;public class TestLock implements Runnable{ private Object object = new Object(); private static int i=0; @Override public void run() { synchronized (object){ increments(); } } private void increments() { for(int j = 0;j < 1000000;j++){ i++; } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new TestLock()); Thread t2 = new Thread(new TestLock()); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(i); }}
因为object属于当前实例的,所以每个线程都有各自的锁,所有存在线程安全问题,结果小于2000万。
2.作用于实例方法,相当于对当前实例加锁,在进入同步代码块前需要先获得当前实例对象的锁
package com.ziwu.learn.thread;public class TestLock implements Runnable{ private static int i=0; @Override public void run() { increments(); } private synchronized void increments() { for(int j = 0;j < 1000000;j++){ i++; } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new TestLock()); Thread t2 = new Thread(new TestLock()); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(i); }}
synchronized用于实例方法上,相当于给当前实例加锁,所以两个线程拥有不同的锁,故而不是线程安全的。
3.作用于静态方法,相当于给当前类加锁,进入同步代码前要获得当前类的锁
package com.ziwu.learn.thread;public class TestLock implements Runnable{ private static int i=0; @Override public void run() { increments(); } private static synchronized void increments() { for(int j = 0;j < 1000000;j++){ i++; } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new TestLock()); Thread t2 = new Thread(new TestLock()); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(i); }}
这段代码的输出结果是正常的,因为静态方法是属于类的,所以相当于两个线程公用一把锁,所以是线程安全的。
看到这里如何将1.1和1.2的方法变成线程安全的那么就很容易了,核心就是让当前两个线程采用一个锁或者将方法声明为static的使用类锁。
package com.ziwu.learn.thread;public class TestLock implements Runnable{ private static int i=0; @Override public void run() { increments(); } private synchronized void increments() { for(int j = 0;j < 1000000;j++){ i++; } } public static void main(String[] args) throws InterruptedException { TestLock test = new TestLock(); Thread t1 = new Thread(test); Thread t2 = new Thread(test); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(i); }}
后面来看一个使用Object.wait(),和Object.notify()让线程协同执行,相比加锁,Object的wait和notify使得个线程可以有序调度。
这两个方法都会抛出 IllegalMonitorStateException异常,需要注意的是wait方法会释放监视器锁,大致语义是是在调用方法的时候没有获取到监视器锁就会异常,简而言之就是该方法得配合synchronized使用,
package com.ziwu.learn.thread;public class TestWait { private static final Object object = new Object(); static class T1 implements Runnable{ @Override public void run() { synchronized (object){ System.out.println("t1 is start"); try { System.out.println("t1 is start wait"); object.wait(); System.out.println("t1 is end wait"); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class T2 implements Runnable{ @Override public void run() { synchronized (object){ System.out.println("t2 is start"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t2 is start notify"); object.notify(); try { Thread.sleep(5000); System.out.println("t2 is end notify"); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Thread t1 = new Thread(new T1()); Thread t2 = new Thread(new T2()); t1.start(); t2.start(); }}
该段代码的输出:
t1 is start
t1 is start wait t2 is start t2 is start notify t2 is end notify t1 is end wait‘可以看到t2在唤醒线程t1后,t1并没有立刻执行因为t2还没有执行完成,故而监视器锁还没有释放,t1此时是拿不到锁的。
转载地址:http://xhazb.baihongyu.com/