java 多线程 同步机制 总结(二)

一.volatile域和final变量

volatile域和final变量 都常被理解为 “程度较轻的 synchronized”,都是为了实现代码线程的安全性,但是没有实现原子性.

volatile 的正确用法:
● 对变量的写操作不依赖于当前值。
● 该变量没有包含在具有其他变量的不变式中。

final也是,如果多个线程在读写final变量,仍然需要使用同步。

二.死锁

如果两个线程都拿了对方需要的锁对象,导致线程无法进行下去,这就会导致死锁产生。

package Thread.lock;

/**
 * 简单的死锁
 * @author panqian
 * @date 2016年12月24日 下午8:14:08
 */
public class DeadLock implements Runnable {

    public int flag = 0;
    //static修饰保证不同的DeadLock对象也共享该Object对象
    static final Object o1 = new Object();
    static final Object o2 = new Object();

    @Override
    public void run() {

        if (flag == 0) {
            synchronized (o1) {
                System.out.println("o1 lock");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (o2) {
                    System.out.println("o2 lock");
                }
            }
        } else {
            synchronized (o2) {
                System.out.println("o2 lock");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (o1) {
                    System.out.println("o1 lock");
                }
            }
        }

    }

}

测试文件

package Thread.test;

import Thread.lock.DeadLock;

public class DeadThread_1 {

    public static void main(String[] str) {
        DeadLock deadLock = new DeadLock();
        DeadLock deadLock2 = new DeadLock();
        deadLock.flag = 0;
        deadLock2.flag = 1;
        final Thread l1 = new Thread(deadLock);
        final Thread l2 = new Thread(deadLock2);
        l1.start();
        l2.start();


        //线程在等待获得锁的时候   你中断操作不能起作用  无法终止
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    l1.interrupt();
                    l2.interrupt();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

三. trylock()的应用 以及用于 优化死锁

上节说死锁会因为获取不到锁 导致死锁的产生 但是trylock方法有一个特性 在于获取不到锁会 返回false 利用这个特性用来避开死锁

package Thread.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * trylock的应用  拿不到锁直接return 避免死锁的情况
 *
 * @author panqian
 * @date 2016年12月24日 下午8:14:08
 */
public class TryDeadLock implements Runnable {

    public int flag = 0;

    static ReentrantLock o1 = new ReentrantLock();
    static ReentrantLock o2 = new ReentrantLock();

    @Override
    public void run() {

        if (flag == 0) {
            if (o1.tryLock()) {
                System.out.println(Thread.currentThread().getName()+": o1 lock");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                if (o2.tryLock()) {
                    System.out.println(Thread.currentThread().getName()+": o2 lock");
                } else {
                    System.out.println(Thread.currentThread().getName()+": return");
                    return;
                }

            } else {
                System.out.println(Thread.currentThread().getName()+": return");
                return;
            }


        }

    else

    {
        if (o2.tryLock()) {
            System.out.println(Thread.currentThread().getName()+": o2 lock");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (o1.tryLock()) {
                System.out.println(Thread.currentThread().getName()+": o1 lock");
            } else {
                System.out.println(Thread.currentThread().getName()+": return");
                return;
            }
        } else {
            System.out.println(Thread.currentThread().getName()+": return");
            return;
        }
    }

}

}

测试类

package Thread.test;

import Thread.lock.DeadLock;
import Thread.lock.TryDeadLock;

/**
 * trylock的应用  拿不到锁直接return 避免死锁的情况
 */
public class TryDeadThread_1 {

    public static void main(String[] str) {
        TryDeadLock deadLock = new TryDeadLock();
        TryDeadLock deadLock2 = new TryDeadLock();
        deadLock.flag = 0;
        deadLock2.flag = 1;
        final Thread l1 = new Thread(deadLock);
        final Thread l2 = new Thread(deadLock2);
        l1.start();
        l2.start();

    }
}

四. 线程局部变量

有时候多个线程不想共享同一个对象的某个变量 想要一个线程局部变量 可以根据如下定义

private static ThreadLocal<Integer> thread = new ThreadLocal<Integer>() {
        //每个线程拿到的初始值为1
        @Override
        protected Integer initialValue() {
            return 1;
        }

    };

每个线程取这个值 或更新这个值

int integer = thread.get();
thread.set(++integer);

五. 读写锁

读写锁的出现是为了提升性能,因为对于单纯的读操作时,是不需要线程同步的,当写锁被获取到时,后续(非当前写操作线程)的读写操作都会被阻塞,写锁释放之后,所有操作继续执行,这样读的操作就能保证是最新的数据

设计一个类,读写分离

package Thread.lock.bean;

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

/**
 * 模拟读写锁
 * 
 * @author panqian
 * @date 2016年12月25日 下午2:35:43
 */
public class Bank_4 extends Bank {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    private Lock readLock = lock.readLock();

    private Lock writeLock = lock.writeLock();

    int num;

    public Bank_4(int num) {
        this.num = num;
    }

    /**
     * 读
     */
    @Override
    public void topUp() {
        readLock.lock();
        try{
            System.out.println(Thread.currentThread().getName()+": 剩余 "+ num);
        }finally {
            readLock.unlock();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    /**
     * 写
     */
    @Override
    public void consume() {
        writeLock.lock();

        try{
            if(num<=0)
                return;
            else
                System.out.println(Thread.currentThread().getName()+": 开始消费"+ --num);
        }finally {
            writeLock.unlock();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}
package Thread.lock;

import Thread.lock.bean.Bank;

/**
 * 模拟读
 * 
 * @author panqian
 * @date 2016年12月21日 下午7:05:28
 */
public class ReadLockRunnable_1 implements Runnable {

    Bank bank;

    public ReadLockRunnable_1(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        while (true) {
            bank.topUp();
        }
    }

}
package Thread.lock;

import Thread.lock.bean.Bank;

/**
 * 模拟写
 * 
 * @author panqian
 * @date 2016年12月21日 下午7:05:28
 */
public class WriteLockRunnable_1 implements Runnable {

    Bank bank;

    public WriteLockRunnable_1(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        while (true) {
            bank.consume();
        }
    }

}

测试类

package Thread.test;

import Thread.lock.ReadLockRunnable_1;
import Thread.lock.WriteLockRunnable_1;
import Thread.lock.bean.Bank_4;

/**
 * 
 * @author panqian
 * @date 2016年12月21日 下午7:05:28
 */
public class ReadWriteLockThread_1 {

    public static void main(String[] args) {

        Bank_4 bank = new Bank_4(300);

        ReadLockRunnable_1 runnable_1 = new ReadLockRunnable_1(bank);
        WriteLockRunnable_1 runnable_2 = new WriteLockRunnable_1(bank);

        for (int i = 0; i < 2; i++) {
            final Thread thread = new Thread(runnable_1);
            thread.start();
        }

        for (int i = 0; i < 2; i++) {
            final Thread thread = new Thread(runnable_2);
            thread.start();
        }

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值