Java并发编程:synchronized
- 什么时候会出现线程安全问题
当多个线程同时访问同一个资源时就有可能出现问题。最终的执行结果和实际上的愿望相违背,或者直接导致程序出错
- 如何解决线程安全问题
基本上所有的并发模式在解决线程安全问题时,都采用了“序列号访问临界资源”的方案。即在同一时刻,只能有一个线程能够访问临界资源,也称作同步互斥访问。
通常来说,在访问临界资源的代码前面加一个锁,当访问结束后释放锁,让其他线程继续访问。
在java中实现了两张方法来实现同步互斥访问 synchronized和lock
- synchronized的使用
互斥锁:能够达到互斥访问的锁。
如果对临界资源加上互斥锁,当一个线程访问临界资源时,其他线程只能等待。
在java中每一个对象都一个锁标记(monitor),也被称为监视器。多线程访问时某个对象时,只有线程获取到了该对象的锁,才能继续访问。
在java中可以直接使用synchronized关键字来标记一段代码或者一个方法。当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。
对于synchronized方法或者synchronized代码块,当代码出现异常时,jvm会自动释放当前线程占用的锁,因此不会因为异常导致死锁。
- 锁方法
public class TestThread { public static void main(String[] args) { final InsertData insertData = new InsertData(); new Thread() { public void run() { insertData.insert(Thread.currentThread()); }; }.start(); new Thread() { public void run() { insertData.insert(Thread.currentThread()); }; }.start(); } } class InsertData { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); public synchronized void insert(Thread thread){ for(int i=0;i<5;i++){ try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(thread.getName()+"在插入数据"+i); arrayList.add(i); } } }
锁住的对象是 insertData ,当创建多个insertData对象分别执行insert方式时,锁就不生效了
- 锁代码块
public class TestThread { public static void main(String[] args) { final InsertData insertData = new InsertData(); new Thread() { public void run() { insertData.insert(Thread.currentThread()); }; }.start(); new Thread() { public void run() { insertData.insert(Thread.currentThread()); }; }.start(); } } class InsertData { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); public void insert(Thread thread){ synchronized(this){ for(int i=0;i<5;i++){ try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(thread.getName()+"在插入数据"+i); arrayList.add(i); } } } }
和方法锁一样
- 锁静态方法
public class TestThread { public static void main(String[] args) { final InsertData insertData = new InsertData(); final InsertData insertData2 = new InsertData(); new Thread() { public void run() { insertData.insert(Thread.currentThread()); }; }.start(); new Thread() { public void run() { insertData2.insert(Thread.currentThread()); }; }.start(); } } class InsertData { private static ArrayList<Integer> arrayList = new ArrayList<Integer>(); public static synchronized void insert(Thread thread){ for(int i=0;i<5;i++){ try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(thread.getName()+"在插入数据"+i); arrayList.add(i); } } }
锁住的类,同一个类的对象都被锁住