Java线程(一):synchronized

来源:互联网 发布:淘宝运营需要学美工吗 编辑:程序博客网 时间:2024/05/22 06:27

一、什么时候会出现线程安全问题?

当多个线程同时访问一个资源(共享资源)时会出现线程安全。资源可以是一个变量、一个对象、一个文件、一个数据库表等。需要注意的是如果多个程序同时访问一个方法,定义在方法内部的局部变量并不是临界资源(共享资源),因为方法是在栈中执行的,而栈是线程私有的,因此不会出现线程安全问题。

二、如何解决线程安全问题?

通常来说在通过对访问共享资源代码加锁,当一个线程来访问时加锁,其他线程等待这个线程释放锁,当前线程执行完后加锁代码后释放锁资源。其他线程就可以访问共享资源了。在Java中,每一个对象都拥有一个锁标记(monitor),也称为监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问。

    Java提供了两种方式来实现同步互斥访问:synchronized和Lock。

三、synchronized同步代码块和同步方法代码示例

package sync;public class TestSynchronized {static TestSynchronized ts = new TestSynchronized();//所有线程共用这一个锁public static void main(String[] args) {new TestSynchronized().new Thread1().start();new TestSynchronized().new Thread2().start();}private void invoke() {try {synchronized (ts) {//同步代码块for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + ":" + "写数据库" + i);Thread.sleep(100);}}} catch (InterruptedException e) {e.printStackTrace();}}class Thread1 extends Thread{public void run(){ts.invoke();}}class Thread2 extends Thread{public void run(){ts.invoke();}}}
运行结果:Thread-0和Thread-1依次执行,没有出现相互竞争执行。

Thread-0:写数据库0
Thread-0:写数据库1
Thread-0:写数据库2
Thread-0:写数据库3
Thread-0:写数据库4
Thread-1:写数据库0
Thread-1:写数据库1
Thread-1:写数据库2
Thread-1:写数据库3
Thread-1:写数据库4

如果将锁加在方法上执行,结果依然一样:

private synchronized void invoke() {try {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + ":" + "写数据库" + i);Thread.sleep(100);}} catch (InterruptedException e) {e.printStackTrace();}}
运行结果:
Thread-0:写数据库0
Thread-0:写数据库1
Thread-0:写数据库2
Thread-0:写数据库3
Thread-0:写数据库4
Thread-1:写数据库0
Thread-1:写数据库1
Thread-1:写数据库2
Thread-1:写数据库3
Thread-1:写数据库4

四、同步方法和同步代码块的区别。

synchronized代码块使用起来比synchronized方法要灵活得多。因为也许一个方法中只有一部分代码只需要同步,如果此时对整个方法用synchronized进行同步,会影响程序执行效率。而使用synchronized代码块就可以避免这个问题,synchronized代码块可以实现只对需要同步的地方进行同步。

五、synchronized需要注意的几点。

1)当一个线程访问一个对象的synchronized方法func1其他线程不能访问这个对象方法func1,因为一个对象只有一个锁。只有释放了锁才能访问func1。

2)当一个线程访问一个对象的synchronized方法func1其他线程可以访问这个对象的非synchronized方法,因为其他方法不需要该对象的锁。

3)如果一个类有static synchronized方法f1和synchronized方法f2,当两个线程分别访问f1和f2时是不会发生互斥的问题,因为一个是对象锁一个是类锁,不是同一个锁。

4)如果synchronized方法或者synchronized代码块发生异常,是不会出现由于异常导致死锁,因为发生异常后JVM会释放锁,这个Lock不一样,lock需要手动释放锁。


原创粉丝点击