public class CurrencyTest {
private static final long count = 1000000001;
/**
* @author PeterS
* @date 2016年5月4日
* @param
* @description
*/
public static void main(String[] args) throws InterruptedException{
currency();
serial();
}
public static void currency() throws InterruptedException {
long start = System.currentTimeMillis();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int a= 0;
for(long i =0;i<count;i++){
a+=5;
}
}
});
thread.start();
int b = 0;
for(long i=0;i<count;i++) b--;
long time = System.currentTimeMillis()-start;
thread.join(); //wait for the thread to die
System.out.println("currency:"+time+"ms,b="+b);
}
public static void serial() {
long start = System.currentTimeMillis();
int a =0,b=0;
for(long i = 0;i<count;i++) a+=5;
for(long i = 0;i<count;i++) b--;
long time = System.currentTimeMillis()-start;
System.out.println("serial:"+time+"ms,b="+b);
}
}
这个是比较结果:count的值 | currency(ms) | serial(ms) |
10001 | 1 | 0 |
1000001 | 3 | 5 |
100000001 | 38 | 73 |
1000000001 | 363 | 695 |
①、无锁并发编程:避免使用锁,例如将数据ID按照hash算法取模分段,不同线程处理不同段的数据 |
②、CAS算法:Atom类,不需要加锁 |
③、使用最少线程 |
④、协程:在单线程中进行多任务的调度和切换 |
public class DeadlockTest {
private static String a = "A";
private static String b = "B";
/**
* @author PeterS
* @date 2016年5月4日
* @param
* @description
*/
public static void main(String[] args) {
new DeadlockTest().deadlock();
}
public void deadlock() {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized(a){
try {
Thread.currentThread().sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(b){
System.out.println("1");
}
}
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
synchronized(b){
synchronized (a) {
System.out.println("2");
}
}
}
});
thread1.start();
thread2.start();
}
}
这段代码就可能出现死锁。如何有效的避免死锁呢?首先要看看死锁的四个必要条件:互斥、请求与保持、不可剥夺、循环等待。所以避免死锁的方法有:
避免一个线程获取多个锁 |
尽量保证每个锁只占有一个资源 |
尝试使用定时锁,lock.trylock(timeout)来代替使用内部锁机制 |
对于数据库锁,加锁和解锁必须放到一个数据库连接里,否则会出现解锁失败 |
ChapterTwo Java并发机制的底层实现原理
1. Java代码的生命流程:Java代码——>Java字节码——>被类加载器加载到JVM中——>JVM执行字节码——>转化成汇编语言——>在CPU上执行2. volatile关键字的应用①volatile关键字保证所有线程看到这个变量是数据一致的,②实现原理:volatile变量会触发两个操作
将当前处理器的缓存行数据写入系统内存 |
这个写回内存的操作会使其他的CPu缓存了该地址的数据无效 |
对于普通同步方法,锁是当前实例对象; |
对于静态同步方法,锁是当前类的Class 对象; |
对于同步代码块,锁是括号()里配置的内容; |
1. 一个不同的Java程序包含哪些线程?
如下代码:
public class MutiThread {
/**
* @author PeterS
* @date 2016年5月4日
* @param
* @description
*/
public static void main(String[] args) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"]"+threadInfo.getThreadName());
}
}
}
2. 在不同的JVM和操作系统中,线程的规划存在差异,有些操作系统可能会忽略线程优先级的设定;3. 线程的状态六种:
状态名称 | 说明 |
NEW | 初始状态,线程被构建,但是还没有调用start()方法 |
RUNNABLE | 就绪状态和运行中状态统称runnable |
BLOCKED | 阻塞状态,表示线程阻塞于锁 |
WAITING | 等待状态 |
TIME_WAITING | 超时等待状态,可在指定的时间自行返回 |
TERMINATED | 终止状态,表示当前的线程已经执行完毕了 |
5. Java线程状态变迁图
6.Daemon线程(守护线程)主要作用于后台调度以及支持性工作,当Java虚拟机中不存在一个Daemon线程时,虚拟机将退出。可以用Thread.setDaemon(true)设置为Daemon线程。7. 优雅的中断线程:通过中断操作和标志位的方式。
public class Shutdown {
public static void main(String[] args) throws Exception{
Runner one = new Runner();
Thread countThread = new Thread(one,"CountThread");
countThread.start();
TimeUnit.SECONDS.sleep(1);
countThread.interrupt(); //用中断操作来终止进程
Runner two = new Runner();
countThread = new Thread(two,"CountThread");
countThread.start();
TimeUnit.SECONDS.sleep(1);
two.cancel(); //设置标志位来中断进程
}
private static class Runner implements Runnable{
private long i;
private volatile boolean on = true;
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
@Override
public void run() {
while(on&&!Thread.currentThread().isInterrupted()){ //判断终止的条件
i++;
}
System.out.println("count i="+i);
}
public void cancel() {
on=false;
}
}
}
8. 等待/通知机制(生产/消费者模型)该范式分为两个部分:等待者(消费者)和通知者(生产者);等待者(消费者):synchronized(object){
while(condition不满足){
object.wait();
}
//to do
}
通知者(生产者):synchronized(object){
改变condition;
object.notifyAll();
}
直接上代码:public class WaitNotify {
static boolean flag = true;
static Object lock = new Object();
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
public static void main(String[] args) {
Thread thread1 = new Thread(new Wait(),"wait");
thread1.start();
SleepUtils.second(1);
Thread thread2 = new Thread(new Notify(),"notify");
thread2.start();
}
static class Wait implements Runnable {
public void run() {
synchronized (lock) {
if (flag) {
try {
System.out.println(Thread.currentThread()+"flag is true.wait@ "+new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.wait();
} catch (Exception e) {
// TODO: handle exception
}
}
System.out.println(Thread.currentThread()+"flag is false.running@ "+new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
static class Notify implements Runnable{
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread()+"hold lock.notify@ "+new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
SleepUtils.second(5);
}
synchronized (lock) {
System.out.println(Thread.currentThread()+"hold lock again.sleep@ "+new SimpleDateFormat("HH:mm:ss").format(new Date()));
SleepUtils.second(5);
}
}
}
public static class SleepUtils{
public static final void second(long sec) {
try {
TimeUnit.SECONDS.sleep(sec);
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
9. 管道传输管道输入输出流主要用于线程之间的数据传输,传输媒介为内存。分为4种表现形式:PipedOutputStream、PipedInputStream、PipedReader、PipedWriter。10. join()含义:如果线程a执行了thread.join(),表示当前线程A等待thread线程终止之后才从thread.join()返回。join(long millis)和join(long millis,int nanos)提供了超时特性,如果线程没有在给定的时间内结束,将返回。11. ThreadLocal使用ThreadLocal是一个线程变量,是一个以ThreadLocal为key,任意对象为value的存储结构。建议深入学习一下。这里不做细致讲解。12. 线程池的实例:ConnectionPool.java
public class ConnectionPool {
private LinkedList<Connection> pool = new LinkedList<>();
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
public ConnectionPool(int initialSize ) {
if (initialSize>0) {
for(int i=0;i<initialSize;i++){
pool.addLast(ConnectionDriver.createConnection());
}
}
}
public void releaseConnection(Connection connection) {
if (connection!=null) {
synchronized (pool) {
//连接释放后需要通知,这样其他消费者可以感知到连接池中已经归还了一个连接
pool.addLast(connection);
pool.notifyAll();
}
}
}
public Connection fetchConnection(long millis) throws InterruptedException{
synchronized (pool) {
//完全超时
if (millis<=0) {
while (pool.isEmpty()) {
pool.wait();
}
return pool.removeFirst();
}
else{
//这是一个超时等待模型,当等待超过一定的时常millis,就直接返回
long future = System.currentTimeMillis()+millis;
long remaining = millis;
while (pool.isEmpty()&&remaining>0) {
pool.wait(remaining);
remaining = future-System.currentTimeMillis();
}
Connection result = null;
if (!pool.isEmpty()) {
result=pool.removeFirst();
}
return result;
}
}
}
}
ConnectionDriver.javapublic class ConnectionDriver {
static class ConnectionHandler implements InvocationHandler{
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("commit")) {
TimeUnit.SECONDS.sleep(100);
}
return null;
}
}
public static final Connection createConnection() {
return (Connection)Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),new Class<?>[]{Connection.class}, new ConnectionHandler());
}
}
ConnectionPoolTest.javapublic class ConnectionPoolTest {
static ConnectionPool pool = new ConnectionPool(10);
static CountDownLatch start = new CountDownLatch(1);
static CountDownLatch end;
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
public static void main(String[] args) throws Exception{
int threadCount = 10;
end = new CountDownLatch(threadCount);
int count = 20;
AtomicInteger got = new AtomicInteger();
AtomicInteger noGot = new AtomicInteger();
for(int i = 0;i<threadCount;i++){
Thread thread = new Thread(new ConnectionRunner(count, got, noGot),"ConnectionRunnerThread");
thread.start();
}
start.countDown();
end.await();
System.out.println("total invoke:"+(threadCount*count));
System.out.println("got connection:"+got);
System.out.println("not got connection:"+noGot);
}
static class ConnectionRunner implements Runnable{
int count;
AtomicInteger got;
AtomicInteger noGot;
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
public ConnectionRunner(int count,AtomicInteger got,AtomicInteger noGot) {
this.count=count;
this.got=got;
this.noGot=noGot;
}
/**
* @author PeterS
* @date 2016年5月5日
* @param
* @description
*/
@Override
public void run() {
try {
start.await();
} catch (Exception e) {
}
while (count>0) {
try {
Connection connection = pool.fetchConnection(1000);
if (connection!=null) {
try {
connection.createStatement();
connection.commit();
} finally{
pool.releaseConnection(connection);
got.incrementAndGet();
}
}
else {
noGot.incrementAndGet();
}
} catch (Exception e) {
}finally {
count--;
}
}
end.countDown();
}
}
}