一.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 thread = new ThreadLocal() {
//每个线程拿到的初始值为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();
}
}
}