Java多线程--线程同步

线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。同步的方法通过锁来实现,每个对象都有且仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。
对于同步的方法,这里先主要学习使用synchronized关键字修饰的方法和锁对象Lock
1、 Synchronized
Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁,也只有在这时,对象锁才起作用。一个对象只有一个锁。如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。也就是说任何其他线程都不能进入该对象上的synchronized方法或代码块,直到持锁线程退出了synchronized同步方法或代码块该锁被释放。(同步只能是同步方法,变量和类不能同步)

package Synchronized20170412;

/**
 * 线程同步的运用
 */
public class Synchronized20170412 {
    public static void main(String[] args) {  
        Fun f = new Fun();
        NewThread new_thread = new NewThread(f);
        Thread thread1 = new Thread(new_thread);
        thread1.start();
        Thread thread2 = new Thread(new_thread);
        thread2.start();
    }

}

class Fun {
    private int total = 0;
    public int getTotal() {
        return total;
    }

    /**
     * 用同步方法实现
     * 
     * @param money
     */
    public synchronized void add(int i) {
        total += i;
    }

    /**
     * 用同步代码块实现
     * 
     * @param money
     */
    public void add1(int i) {
        synchronized (this) {
            total += i;
        }
    }
}

class NewThread implements Runnable {
    private Fun f;

    public NewThread(Fun f) {
        this.f = f;
    }

    public void run() {
        //System.out.println(Thread.currentThread().getName() + " Total = " + f.getTotal());
        for (int i = 0; i < 5; i++) {
            f.add1(10);
            //f.add(10);
            System.out.println(Thread.currentThread().getName() + " i = " + i + " Total = " + f.getTotal());
        }
    }
}

结果如下:


Java多线程--线程同步_第1张图片
Paste_Image.png

可以看到线程0和线程1之间只有等待对方释放锁后,自己才能获得锁并在Total上加10,他们之间的操作不会有冲突.

2、 Lock
Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作
与synchronized的区别:
Lock可以使用Condition进行线程之间的调度,Synchronized则使用Object对象本身的notify, wait, notityAll调度机制。
Condition(即对象监视器)是Java5以后出现的机制,它有更好的灵活性,在一个对象里面可以有多个Condition,则线程可以注册在不同的Condition,从而可以有选择性的调度线程,更加灵活。他并不是一种替代内置加锁的方法,而是当内置加锁机制不适用时,作为一种可选择的高级功能,lock接口提供了一种无条件的、可轮询的、定时的以及可中断的锁获取机制,所有的加锁和解锁方法都是显示的
Synchronized就相当于整个对象只有一个单一的Condition(即该对象本身)所有的线程都注册在它身上

package Lock20170412;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Lock20170412 {  
    public static void main(String[] args) {  
        Fun f = new Fun();
        NewThread new_thread = new NewThread(f);
        Thread thread1 = new Thread(new_thread);
        thread1.start();
        Thread thread2 = new Thread(new_thread);
        thread2.start(); 
    }  
}  


class Fun {
    private int total = 0;
    public int getTotal() {
        return total;
    }

    public void add(int i) {
        total += i;
    }
}

class NewThread implements Runnable {
    private Fun f;
    private Lock lock = new ReentrantLock();// 锁对象 

    public NewThread(Fun f) {
        this.f = f;
    }

    public void run() {
        lock.lock();// 得到锁 
        try {
            for (int i = 0; i < 5; i++) {
                f.add(10);
                System.out.println(Thread.currentThread().getName() + " i = " + i + " Total = " + f.getTotal());
            }
        } finally {  
            lock.unlock();// 释放锁  
        }  
    }
}  

结果如下:


Java多线程--线程同步_第2张图片
Paste_Image.png

可以看到线程0执行完毕后才释放锁,线程1得到锁后才开始执行

你可能感兴趣的:(Java多线程--线程同步)