线程安全三性
原子性:
可见性:volatile声明的字段可见
有序性:
线程安全(jdk1.8)
守护线程:Daemon
守护线程会随着主线程的结束而结束
package com.share.code.test;
public class TestTheadDaemon implements Runnable {
private static Integer integer = 0;
public static void main(String[] args) throws Exception {
TestTheadDaemon thead = new TestTheadDaemon();
Thread t1 = new Thread(thead);
t1.setDaemon(true);//设置守护线程,必须在start()之前
t1.start();
t1.join();
System.out.println(integer);
}
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
integer++;
}
}
}
线程的安全之-synchronize:
synchronize:使用方式:普通方法内部,普通方法上,静态方法上(类锁)
package com.share.code.test;
public class TestThead2 {
private static Integer integer = 0;
private static final Object OBJECT = new Object();
public static void main(String[] args) throws Exception {
// Thread t1 = new Thread(() -> sum());
// Thread t2 = new Thread(() -> sum());
// t1.start();
// t2.start();
// t1.join();
// t2.join();
TestThead2 thTestThead2 = new TestThead2();
// Thread t3 = new Thread(() -> thTestThead2.sum2());
// Thread t4 = new Thread(() -> thTestThead2.sum2());
// t3.start();
// t4.start();
// t4.join();
// t4.join();
Thread t5 = new Thread(() -> thTestThead2.sum3());
Thread t6 = new Thread(() -> thTestThead2.sum3());
t5.start();
t6.start();
t5.join();
t6.join();
System.out.println(integer);
}
/**
* static 当前类锁
*/
public static synchronized void sum() {
for (int i = 0; i < 100000; i++) {
integer++;
}
}
/**
* 同一个调用对象加锁
*/
public synchronized void sum2() {
for (int i = 0; i < 100000; i++) {
integer++;
}
}
/**
* 使用对象加锁
*/
public synchronized void sum3() {
for (int i = 0; i < 100000; i++) {
synchronized (OBJECT) {
integer++;
}
}
}
}
隐蔽的错误:边界、线程中的错误
动态改变的基本类型的包装类,不能用来作为synchronize锁对象,例如如下代码,得到的值小于200000:
package com.share.code.test;
public class TestThead implements Runnable {
private static Integer integer = 0;
private static final TestThead TESTTHEAD = new TestThead();//使用作为synchronized 加锁看看效果
public static void main(String[] args) throws Exception {
TestThead thead = new TestThead();
Thread t1 = new Thread(thead);
Thread t2 = new Thread(thead);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(integer);
}
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
synchronized (integer) {
integer++;
}
}
}
}
线程的安全之-ReentrantLock (重入锁):
重入锁:ReentrantLock ,默认是非公平锁,new ReentrantLock(true)设置为公平锁
package com.share.code.test;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentrantLock implements Runnable {
static ReentrantLock lock = new ReentrantLock();
private static Integer integer = 0;
public static void main(String[] args) throws Exception {
TestReentrantLock thead = new TestReentrantLock();
Thread t1 = new Thread(thead);
Thread t2 = new Thread(thead);
// Thread t1 = new Thread(new TestReentrantLock());
// Thread t2 = new Thread(new TestReentrantLock());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(integer);
}
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
lock.lock();
try {
integer++;
} finally {
lock.unlock();
}
}
}
}
非公平锁源码:
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
公平锁源码:
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
线程的安全之-ReentrantLock-Condition
类似于Object中的wait(),notify(),notifyAll()
package com.share.code.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 重入锁-ReentrantLock-Condition
*
* @author Administrator
*
*/
public class TestReentrantLockCondition implements Runnable {
static ReentrantLock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void main(String[] args) throws Exception {
TestReentrantLockCondition thead = new TestReentrantLockCondition();
Thread t1 = new Thread(thead);
t1.start();
Thread.sleep(2000);
lock.lock();
condition.signal();
lock.unlock();
}
@Override
public void run() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "等待");
condition.await();
System.out.println(Thread.currentThread().getName() + "等待结束");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition在Jdk中的使用,比如:ArrayBlockingQueue,关键源码:
public ArrayBlockingQueue(int capacity) {
//默认是非公平锁
this(capacity, false);
}
/**
* Creates an {@code ArrayBlockingQueue} with the given (fixed)
* capacity and the specified access policy.
*
* @param capacity the capacity of this queue
* @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order;
* if {@code false} the access order is unspecified.
* @throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();//等待
enqueue(e);
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();//等待
return dequeue();
} finally {
lock.unlock();
}
}
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();//唤醒
}
/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.
*/
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//唤醒
return x;
}
小技巧
命令: jps,用来显示JVM虚拟机进程号
jstack pid(进程号) 用来显示堆栈信息
该博客围绕Java多线程的线程安全展开,介绍了线程安全三性,提及守护线程会随主线程结束而结束。还阐述了保障线程安全的方法,如synchronize、ReentrantLock(重入锁)及ReentrantLock - Condition,最后给出查看JVM进程号和堆栈信息的命令。
359

被折叠的 条评论
为什么被折叠?



