java进阶整理(一)

该博客围绕Java多线程的线程安全展开,介绍了线程安全三性,提及守护线程会随主线程结束而结束。还阐述了保障线程安全的方法,如synchronize、ReentrantLock(重入锁)及ReentrantLock - Condition,最后给出查看JVM进程号和堆栈信息的命令。

线程安全三性

原子性:
可见性: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(进程号) 用来显示堆栈信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值