java并发编程——线程同步

sysynchronized关键字能够修饰方法、代码块,但不能修饰构造器、成员变量等。java

当sysynchronized关键字同来修饰方法和代码块时,可以保证同一时刻最多只有一个线程执行该段代码或方法。防止当有两个线程并发修改同一个文件时可能会形成异常。编程

同步代码块语法:安全

synchronized(obj){
        ...
        //此处代码是同步代码块
    }
复制代码

意思为:当线程要执行如下代码块以前,必须先得到对obj的锁。bash

当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一个时间内只能有一个线程获得执行。另外一个线程必须等待当前线程执行完代码块之后才能执行该代码块。

然而,另外一个当一个线程访问object的一个synchronized(this)代码块时,另外一个线程仍然能够访问该object中的非synchronized(this)同步代码块,可是其余线程对object中其余全部的synchronized(this)同步代码块的访问将被阻塞并发

示例:ide

public class Thread1 {

    public void synchronize() {
        synchronized (this) {
            System.out.println("I am the synchronized part:");
            for (int i=0; i<3; i++) {
                System.out.println(Thread.currentThread().getName()+":"+(i+1));
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("the synchronized part is over");
        }
    }

    public void synchronize2() {
        synchronized (this) {
            System.out.println("I am the synchronized part 2:");
            for (int i=0; i<3; i++) {
                System.out.println(Thread.currentThread().getName()+":"+(i+1));
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("the synchronized part 2 is over");
        }
    }

    public void nonSynchronize() {
        System.out.println("non-synchronized part:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the non-synchronized part is over");
    }

    public static void main(String[] args) {
        final Thread1 thread1 = new Thread1();

    //启动线程,线程一、2和3分别用了不一样的表达式
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                thread1.synchronize();
            }
        });
        Thread t2 = new Thread(() -> thread1.synchronize2());
        Thread t3 = new Thread(thread1::nonSynchronize);
        t1.start();
        t2.start();
        t3.start();
    }
}复制代码

输出结果:工具


从输出结果能够看出:线程0执行的是第一个同步代码块,线程2执行的是非同步代码块,线程0和2同时执行,二者互不干扰。线程1执行的是第二个同步代码块,由于线程0先得到对该对象的锁定,因此线程1即便执行代码块跟线程0不同,也被阻塞,必须等线程1执行完同步代码块,释放锁,线程1才能继续执行。this

同步方法示例

public class Thread1 {

    private synchronized void synchronize() {
        System.out.println("I am the synchronized method part:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the synchronized method part is over");
    }

    private synchronized void synchronize2() {
        System.out.println("I am the synchronized method part 2:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the synchronized method part 2 is over");
    }

    private  void nonSynchronize() {
        System.out.println("non-synchronized method part:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the non-synchronized method part is over");
    }

    public static void main(String[] args) {
        final Thread1 thread1 = new Thread1();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                thread1.synchronize();
            }
        });
        Thread t2 = new Thread(() -> thread1.synchronize2());
        Thread t3 = new Thread(thread1::nonSynchronize);
        t1.start();
        t2.start();
        t3.start();
    }
}复制代码

输出结果跟同步代码块同样:spa


同步锁

Lock 是控制多个线程对共享资源进行访问的工具。每次只能有一个线程对Lock对象加锁,线程开始访问共享资源以前应先得到Lock对象。.net

在实现线程安全的控制中,比较经常使用的是ReentrantLock。

class X {
    private final ReentrantLock lock = new ReentrantLock();
    //定义须要保证线程安全的方法
    public void m() {
        //加锁
        lock.lock();
        try {
            //method body
        } finally { //使用finally来保证释放锁
            lock.unlock();
        }
    }
}复制代码


参考资料:java加锁与同步方法

疯狂java讲义(第三版)

Java编程思想(第4版)

相关文章
相关标签/搜索