最近一直在学习和实践JAVA并发编程,也从书中总结了一些经验,在这里书写一下可以马上上手利用的内容,日后再慢慢补充完善。
1.在构建守护线程时,不能依靠finally块中的内容,来确保执行关闭或清理资源的逻辑。
有如下示例代码:
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("理论上,是执行不了这个方法的,因为线程是守护线程");
}
}
});
thread.setDaemon(true);
thread.start();
System.out.println("Main线程执行完毕");
}
}
运行结果是只会打印出“Main线程执行完毕这一句话”
2.java.util.concurrent.atomic包提供了高效的,线程安全地更新一个变量方式。
2.1原子更新基本类型类:原子方式更新基本数据类型
public class Main {
// 哪怕这里加了volatile也是没用的,因为volatile可以保证线程之间的可见性,并不能保证原子性
static volatile int n = 0;
static AtomicInteger m = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
@Override
public void run() {
// 这里结束的数值不能设置得太小,因为太小的话,速度太快,无法体现出效果
for (int i = 0; i < 10000; i++) {
// 你这里写成n = n + 1或者n +=1,也是一样基本得不到正确结果的
n++;
m.incrementAndGet();
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
n++;
m.incrementAndGet();
}
}
};
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("n" + n);
System.out.println("m" + m.get());
}
}
public class Main {
static volatile CountDownLatch latch = new CountDownLatch(2);
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("线程1准备睡眠");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("线程1睡眠结束");
latch.countDown();
}
};
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println("线程2准备睡眠");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("线程2睡眠结束");
latch.countDown();
}
};
t1.start();
t2.start();
System.out.println("main线程要准备被阻塞了");
latch.await();
System.out.println("main线程得以继续执行");
}
}
运行结果:
// 为了显示时间方便,直接使用了new Date().toLocaleString(),但是这是一个被废弃的方法,而且实际开发中,不应该这样写
public class Main {
static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
public void run() {
System.out.println("已经有两个线程执行了await()方法了"
+ new Date().toLocaleString());
}
});
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("线程1准备睡眠" + new Date().toLocaleString());
try {
Thread.sleep(1000);
System.out.println("线程1睡眠结束" + new Date().toLocaleString());
cyclicBarrier.await();
} catch (Exception e) {
}
System.out.println("线程1await结束" + new Date().toLocaleString());
}
};
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println("线程2准备睡眠" + new Date().toLocaleString());
try {
Thread.sleep(2000);
System.out.println("线程2睡眠结束" + new Date().toLocaleString());
cyclicBarrier.await();
} catch (Exception e) {
}
System.out.println("线程2await结束" + new Date().toLocaleString());
}
};
t1.start();
t2.start();
System.out.println("main线程要准备被阻塞了" + new Date().toLocaleString());
System.out.println("main线程得以继续执行" + new Date().toLocaleString());
}
}
public class Main {
static Object object = new Object();
public static void main(String[] args) throws Exception {
methodA();
}
public static void methodA() {
System.out.println("methodA想锁住了object");
synchronized (object) {
System.out.println("methodA锁住了object,并且准备调用methodB");
methodB();
}
}
public static void methodB() {
// 因为JAVA的锁是可重入的,所以这里另开一个线程
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("methodB想锁住了object");
synchronized (object) {
System.out.println("methodB锁住了object,并且准备调用methodA");
methodA();
}
}
};
thread.start();
try {
// methodB想等待线程执行完之后,才结束,但是它不知道methodA调用methodB的时候,已经锁上了object,而methodB又在线程中企图锁object,于是就发送了死锁。这是一种容易被忽略的死锁情况
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//一个独占锁的简易实现(不可重入)
class Mutex implements Lock {
private static class Sync extends AbstractQueuedSynchronizer {
/**
*
*/
private static final long serialVersionUID = -642099341499014369L;
/**
* 是否处于占用状态
*/
@Override
protected boolean isHeldExclusively() {
// 1表示锁被占用
return getState() == 1;
}
/**
* 当状态为0的时候获取锁
*/
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
/**
* 释放锁并将状态设置为0
*/
@Override
protected boolean tryRelease(int arg) {
if (getState() == 0) {
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
Condition newCondition() {
return new ConditionObject();
}
}
private final Sync sync = new Sync();
public void lock() {
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.tryAcquire(1);
}
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
}
支持多个线程同时访问的锁(不可重入)
// 支持共享式访问(即同一时刻支持多个线程访问)
class ArbitraryCountLock implements Lock {
private int lockCount = 2;
private final Sync sync;
public ArbitraryCountLock(int lockCount) {
super();
this.lockCount = lockCount;
sync = new Sync(lockCount);
}
public void lock() {
sync.acquireShared(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean tryLock() {
return sync.tryAcquireShared(1) > 0 ? true : false;
}
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
}
public void unlock() {
sync.releaseShared(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public int getLockCount() {
return lockCount;
}
private static class Sync extends AbstractQueuedSynchronizer {
/**
*
*/
private static final long serialVersionUID = -642099341499014369L;
Sync(int count) {
if (count < 1) {
throw new RuntimeException("锁的数量最小为1");
}
setState(count);
}
// 在失败时返回负值;如果共享模式下的获取成功但其后续共享模式下的获取不能成功,则返回
// 0;如果共享模式下的获取成功并且其后续共享模式下的获取可能够成功,则返回正值
@Override
protected int tryAcquireShared(int reduceCount) {
while (true) {
int current = getState();
int newCount = current - reduceCount;
if (newCount < 0 || compareAndSetState(current, newCount)) {
return newCount;
}
}
}
@Override
protected boolean tryReleaseShared(int returnCount) {
while (true) {
int current = getState();
int newCount = current + returnCount;
if (compareAndSetState(current, newCount)) {
return true;
}
}
}
Condition newCondition() {
return new ConditionObject();
}
}
}
static Object |
getBlocker(Thread t) 返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。 |
static void |
park() 为了线程调度,禁用当前线程,除非许可可用。 |
static void |
park(Object blocker) 为了线程调度,在许可可用之前禁用当前线程。 |
static void |
parkNanos(long nanos) 为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。 |
static void |
parkNanos(Object blocker, long nanos) 为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。 |
static void |
parkUntil(long deadline) 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。 |
static void |
parkUntil(Object blocker, long deadline) 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。 |
static void |
unpark(Thread thread) 如果给定线程的许可尚不可用,则使其可用。 |