1.进程与线程:
线程:一个进程可以拥有多个并行的线程,线程是进程中一个程序执行控制的单元
进程:由cpu,data,code三部分组成,每个进程都是独立的,由系统分配,进程间的切换开销较大,进程基于操作系统;
2.并行与并发
并发:多个线程访问同一份资源
并行:在多个cpu情形下,多个线程同时运行
3.线程数与运行时间
线程数:我们看到的虚拟机里面显示的线程数,是虚拟的线程数,例如单线程,他是将时间分成很多小的时间片,不同的时间片会调用不同的虚拟的线程程序段,当调用这个程序是其他程序会挂起
运行时间:运行时间与实际的线程数有直接联系,过多的线程容易引起并发等问题,所以不一定快
4.线程间的通信
通信机制有两种:共享内存和消息传递
共享内存的并发模型里,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过发送消息来显式进行通信。Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式进行,整个通信过程对程序员完全透明,
5.内存的可见性
堆内存在线程之间共享。局部变量,方法定义参数和异常处理器参数不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。
6.实现多线程的3种方式
Thread类:
步骤:
1>定义类继承Thread类;
2>复写run方法;
3>创建Thread类的子类对象来创建线程对象;
4>调用线程的start方法,开启线程,并执行run方法。
备注 : sleep 和wait的区别,一个会释放锁,一个不会释放锁
public class JoinTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread( new JoinTestA(),"线程1");thread.start();thread.join();System.out.println("hello world");}
}
class JoinTestA implements Runnable {@Overridepublic void run() {System.out.println("hello join");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}
public class DaemonTest2 {public static void main(String[] args) {Thread thread = new Thread(new DaemonTestB() );
//设置为守护线程的时候 ,需要是没有开启的线程,否则会报错,thread.setDaemon(true);thread.start();new Thread(new DaemonTestA() ).start();}
}class DaemonTestA implements Runnable {@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(1111);}}
class DaemonTestB implements Runnable {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(2222);}}
Runnable接口
步骤:
1>定义类实现Runnable接口。
2>覆盖接口中的run方法。
3>通过Thread类创建线程对象;
4>将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
5>调用线程的start方法,开启线程,并执行run方法。
Callable接口
步骤:
1>定义类实现callable接口。
2>复写接口中的call方法。
3>创建FutureTask对象,并且将实现了callable作为对象传入
4> 将FutureTask对象作为实际参数传递给Thread类中的构造函数
5>调用线程的start方法,开启线程,并执行call方法
备注:Callable具有返回值,但还是相应的FutureTask的get方法是一个阻塞式的方法,需要获取在start之后有值,假如在start之前书写get方法,那么一直会处于阻塞状态,当我们在线程池中使用的是FutureTask对象,那么submit后的引用的get方法取不到值,但可以用FutureTask对象的get方法去得到值,只有使用callable的submit后的引用的get方法能取到值
//jion方法
public class ThreadTest {public static void main(String[] args) throws InterruptedException, ExecutionException {ThreadTestA threadTestA = new ThreadTestA();threadTestA.setName("A");threadTestA.start();Thread threadB = new Thread(new ThreadTestB(), "B");threadB.start();FutureTask<String> futureTask = new FutureTask<>(new ThreadTestC());Thread threadC = new Thread(futureTask, "C");threadC.start();String string = futureTask.get();System.out.println(string);} }class ThreadTestA extends Thread {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ":hello thread");}}class ThreadTestB implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ":hello runnable");}}class ThreadTestC implements Callable<String> {@Overridepublic String call() throws Exception {return Thread.currentThread().getName() + ":HELLO CALLABLE";}}
//sleep和wait的区别
//sleep 不会释放锁,也不会释放线程 处于阻塞状态
//wait 会释放锁,不会释放线程,处于阻塞状态
public class SleepAndWait {public static void main(String[] args) throws InterruptedException {SleepTest sleepTest = new SleepTest();CountDownLatch countDownLatch = new CountDownLatch(2);long start = System.currentTimeMillis();for (int i = 0; i < 2; i++) {new Thread(new Runnable() {public void run() {try {sleepTest.testA();} catch (InterruptedException e) {e.printStackTrace();}countDownLatch.countDown();}}).start();}countDownLatch.await();long end = System.currentTimeMillis();System.out.println(end - start);// 4001WaitTest waitTest = new WaitTest();CountDownLatch countDownLatch1 = new CountDownLatch(2);start = System.currentTimeMillis();for (int i = 0; i < 2; i++) {new Thread(new Runnable() {public void run() {try {System.out.println(Thread.currentThread().getName() + ":hello");// 回到阻塞状态waitTest.testA();} catch (InterruptedException e) {e.printStackTrace();}countDownLatch1.countDown();}}).start();}countDownLatch.await();end = System.currentTimeMillis();System.out.println(end - start);// 4001}
}class SleepTest {public synchronized void testA() throws InterruptedException {Thread.sleep(1000);;}
}class WaitTest {public synchronized void testA() throws InterruptedException {this.wait();}
}
//yield会放弃线程,然后调用优先级较高的,但这个方法不是绝对可行的,只是概率型事件
//相应的也会将相应的位置放入栈中,下次调度的时候回到相应的位置
public static void main(String[] args) {A a = new A();Thread threadA = new Thread(a,";程A");B b = new B();Thread threadB = new Thread(b,";程B");threadA.start();threadB.start();
}
}
class A implements Runnable{@Overridepublic void run() {System.out.println(1);Thread.yield();System.out.println(2);}
}
class B implements Runnable{@Overridepublic void run() {System.out.println(3);Thread.yield();System.out.println(4);}
}//可能会调用到自己 3 4 1 2的出现
7.线程池基本使用
7.1向线程池中添加线程,需实现了callable接口或者runnable接口
线程池的体系结构:
java.util.concurrent.Executor : 负责线程的使用与调度的根接口
ExecutorService : 线程池的主要接口
ThreadPoolExecutor 线程池的实现类
ScheduledExecutorService :负责线程的调度
ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
7.2工具类:Executors
ExecutorService newFixedThreadPool() : 创建固定大小的线程池
ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
备注一下:api方法前带new表示新建的对象,不带new表示原对象
public class ThreadTest {public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);//创建固定的线程池newFixedThreadPool.submit(new ThreadTestA());newFixedThreadPool.submit(new ThreadTestB());Future<String> submit = newFixedThreadPool.submit(new ThreadTestC());String string2 = submit.get();System.out.println(string2);newFixedThreadPool.shutdown();//线程执行完成后关闭,不在接受新的任务 shutdownNow试图关闭所有正在执行的任务ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);//每个10s执行一次,初始在1s后执行newScheduledThreadPool.scheduleWithFixedDelay(new ThreadTestA(), 1, 10, TimeUnit.SECONDS);//一秒后执行执行一次newScheduledThreadPool.schedule(new ThreadTestB(), 1, TimeUnit.SECONDS);
newFixedThreadPool.shutdown();
newScheduledThreadPool.shutdown();
} }class ThreadTestA extends Thread {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ":hello thread");}}class ThreadTestB implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ":hello runnable");}}class ThreadTestC implements Callable<String> {@Overridepublic String call() throws Exception {return Thread.currentThread().getName() + ":HELLO CALLABLE";}}
8.线程池的基本原理
1)线程池判断核心线程池里的线程是否都在执行任务。如果没有则创建核心线程去执行任务,如果核心线程池里的线程都在执行任务;然后线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,然后线程池判断线程池的最大的线程数是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。线程超出 maximumPoolSize,在这种情况下,任务将被拒绝;然后多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止.
线程池的底层实现:
volatile int runState;
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
当线程数小于核心线程数的时候,如下会创建一个线程去执行,创建后处于死循环状态
private boolean addIfUnderCorePoolSize(Runnable firstTask) {Thread t = null;final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {if (poolSize < corePoolSize && runState == RUNNING)t = addThread(firstTask); //创建线程去执行firstTask任务 } finally {mainLock.unlock();}if (t == null)return false;t.start();return true;
}
当大于核心线程数而阻塞队列没有满时,死循环的线程不断从阻塞队列中获取任务
public void run() {try {Runnable task = firstTask;firstTask = null;while (task != null || (task = getTask()) != null) {runTask(task);task = null;}} finally {workerDone(this);}
}
Runnable getTask() {for (;;) {try {int state = runState;if (state > SHUTDOWN)return null;Runnable r;if (state == SHUTDOWN) // Help drain queuer = workQueue.poll();else if (poolSize > corePoolSize || allowCoreThreadTimeOut) //如果线程数大于核心池大小或者允许为核心池线程设置空闲时间,//则通过poll取任务,若等待一定的时间取不到任务,则返回nullr = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);elser = workQueue.take();if (r != null)return r;if (workerCanExit()) { //如果没取到任务,即r为null,则判断当前的worker是否可以退出if (runState >= SHUTDOWN) // Wake up othersinterruptIdleWorkers(); //中断处于空闲状态的workerreturn null;}// Else retry} catch (InterruptedException ie) {// On interruption, re-check runState}}
}
如果线程池处于STOP状态、或者任务队列已为空或者设置allowCoreThreadTimeout为true时(核心线程也退出,假如设置为false,默认为false,核心线程数一般不会关闭),并且线程数大于1时,允许worker退出。如果允许worker退出,则调用interruptIdleWorkers()中断处于空闲状态的worker
void interruptIdleWorkers() {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {for (Worker w : workers) //实际上调用的是worker的interruptIfIdle()方法w.interruptIfIdle();} finally {mainLock.unlock();}
}
void interruptIfIdle() {final ReentrantLock runLock = this.runLock;if (runLock.tryLock()) { //注意这里,是调用tryLock()来获取锁的,因为如果当前worker正在执行任务,锁已经被获取了,是无法获取到锁的//如果成功获取了锁,说明当前worker处于空闲状态try {if (thread != Thread.currentThread()) thread.interrupt();} finally {runLock.unlock();}}
}
备注:也就是说能添加的最大的任务数是最大的线程数+BlockingQueue工作队列
2)被拒绝执行任务时的策略
ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。
ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。
ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。
ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。
3)线程池都是通过 ThreadPoolExecutor这个核心类来创建的,我们自定义线程池也可以用这个类来实现,最终是通过ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)来实现的,在newFixedThreadPool和newSingleThreadExecutor以及newCachedThreadPool都是使用的默认的RejectedExecutionHandler defaultHandler =new AbortPolicy()策略。
4)自定义线程池
public class MyExcutorsTest {public static void main(String[] args) {// ThreadPoolExecutor(int corePoolSize, 核心线程数// int maximumPoolSize, 最大线程数// long keepAliveTime, 超过核心线程数小于最大线程数的保持空闲时间// TimeUnit unit, 时间单位// BlockingQueue<Runnable> workQueue, 阻塞队列// ThreadFactory threadFactory, 线程工厂// RejectedExecutionHandler handler) 被拒绝执行任务时的策略ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 2, 5, TimeUnit.SECONDS,new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new AbortPolicy());for (int i = 0; i < 6; i++) {threadPoolExecutor.submit(new MyExcutorsTest().new MyExcutorsTestA());/** 结果 2(最大)+3(阻塞队列)=5大于五抛出异常 pool-1-thread-1 pool-1-thread-2* pool-1-thread-1 pool-1-thread-2 pool-1-thread-1* //抛出异常java.util.concurrent.RejectedExecutionException异常*/}threadPoolExecutor.shutdown();}class MyExcutorsTestA implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
9.BlockingQueue:阻塞队列,实现是线程安全的
1)定义:支持阻塞的插入方法:当阻塞队列已满时,队列会阻塞插入元素的线程,直到队列不满;支持阻塞的移除方法:队列为空时,获取元素的线程会等待队列变为非空。类似于一个生产者和消费者模式,生产者类似于插入,消费者类似于移除,而队列就是仓库
2)对于队列已满时继续插入具有4种策略
抛出异常:当队列满时,如果再往队列里插入元素,会抛出IllegalStateException("Queuefull")异常。当队列空时,从队列里获取元素会抛出NoSuchElementException异常。add,remove,element方法
返回特殊值:当往队列插入元素时,会返回元素是否插入成功,成功返回true。如果是移除方法,则是从队列里取出一个元素,如果没有则返回null。offer poll peek 方法
一直阻塞:当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断退出。当队列空时,如果消费者线程从队列里take元素,队列会阻塞住消费者线程,直到队列不为空。 put take
超时退出:当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定的时间,生产者线程就会退出。 offer poll方法
备注:如果是无界阻塞队列,队列不可能会出现满的情况,所以使用put或offer方法永远不会被阻塞,而且使用offer方法时,该方法永远返回true。
3)java中提供了7个阻塞队列
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。按照先进先出(FIFO)的原则对元素进行排序。在默认插入队列时并不保证公平性,可以设置
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列则,默认值是 Integer.MAX_VALUE,(newFixedThreadPool和newSingleThreadExecutor使用的就是这种队列),此队列按照先进先出的原则对元素进行排序
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。默认情况下元素采取自然顺序升序排列
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列,newCachedThreadPool使用的就是这种队列),每一个put操作必须等待一个take操作,否则不能继续添加元素,默认情况下线程采用非公平性策略访问队列,使用以下构造方法可以创建公平性访问的SynchronousQueue,如果设置为true,则等待的线程会采用先进先出的顺序访问队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
10.volatile与synchronized及atomic
volatile:只保证内存的可见性,并不保证原子性,synchronized的轻量级算法
synchronized:保证内存的可见性以及原子性
atomic:cas算法保证内存的可见性以及原子性
cas算法:有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
public class VolatileTest2 {//死循环输出,因为while(true)的效率是非常的高的,验证共享机制@Testpublic void test() {VolatileTestC volatileTestC = new VolatileTestC();new Thread(volatileTestC).start();while(true){if(VolatileTestC.flag2){System.out.println("flag2");break;}}}
}
//每个线程自己有自己的内存,--验证共享内存机制
class VolatileTestC implements Runnable{public static boolean flag2;@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}flag2=true;System.out.println("flag=true");}
}
public class VolatileTest2 {//死循环输出,因为while(true)的效率是非常的高的@Testpublic void test() {VolatileTestC volatileTestC = new VolatileTestC();new Thread(volatileTestC).start();while(true){if(VolatileTestC.flag2){System.out.println("flag2");break;}}}
}
//每个线程自己有自己的内存,--验证共享内存机制 --volatile保证内存的可见性
class VolatileTestC implements Runnable{public static volatile boolean flag2;@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}flag2=true;System.out.println("flag=true");}
}
//volatile不能保证原子性
public class VolatileAtomicTest {public static void main(String[] args) {
VolatileAtomicTestA volatileAtomicTestA=new VolatileAtomicTestA();for (int i = 0; i < 10; i++) {new Thread(volatileAtomicTestA).start();}}
}
class VolatileAtomicTestA implements Runnable {public volatile static int i=10;@Overridepublic void run(){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+":"+test());}public int test(){return i--;}
}
/*输出
Thread-0:10
Thread-2:10
Thread-1:9
Thread-5:8
Thread-6:5
Thread-3:6
Thread-9:7
Thread-4:4
Thread-8:3
Thread-7:2
*/
public class AtomicTest {public static void main(String[] args) {AtomicTestA atomicTestA = new AtomicTestA();for (int i = 0; i < 10; i++) {new Thread(atomicTestA).start();}}
}
class AtomicTestA implements Runnable {//AtomicInteger 使用的是对象锁public AtomicInteger atomicInteger =new AtomicInteger (10);@Overridepublic void run(){System.out.println(Thread.currentThread().getName()+":"+test());}//atomicIntegerpublic int test(){return atomicInteger.decrementAndGet();}
}
/*
Thread-0:8
Thread-5:4
Thread-3:9
Thread-4:5
Thread-1:7
Thread-2:6
Thread-7:2
Thread-6:3
Thread-8:1
Thread-9:0
*/
public class TestCompareAndSwap {public static void main(String[] args) {CompareAndSwap cas = new CompareAndSwap();for (int i = 0; i < 100; i++) {new Thread(new Runnable() {@Overridepublic void run() {int expectedValue = cas.get();//会争抢锁//假如在这里加一个线程延时那么会基本上是falseboolean b = cas.compareAndSet(expectedValue, (int)(Math.random() * 101));System.out.println(b);}}).start();}}}class CompareAndSwap{private int value;//获取内存值public synchronized int get(){return value;}//比较public synchronized int compareAndSwap(int expectedValue, int newValue){int oldValue = value;if(oldValue == expectedValue){this.value = newValue;}return oldValue;}//设置public synchronized boolean compareAndSet(int expectedValue, int newValue){return expectedValue == compareAndSwap(expectedValue, newValue);}
}
public class StaticLockAndLock {public static void main(String[] args) throws InterruptedException {StaticLockAndLockTest staticLockAndLockTest = new StaticLockAndLockTest();CountDownLatch countDownLatch = new CountDownLatch(2);long start = System.currentTimeMillis();new Thread(new Runnable() {public void run() {try {StaticLockAndLockTest.testA();} catch (InterruptedException e) {e.printStackTrace();}countDownLatch.countDown();}}).start();new Thread(new Runnable() {public void run() {try {staticLockAndLockTest.testB();} catch (InterruptedException e) {e.printStackTrace();}countDownLatch.countDown();}}).start();countDownLatch.await();long end = System.currentTimeMillis();System.out.println(end - start);}
}class StaticLockAndLockTest {// 使用的锁是字节码--类锁public static synchronized void testA() throws InterruptedException {Thread.sleep(1000);System.out.println(111111111);}// 使用的锁是对象---对象锁public synchronized void testB() throws InterruptedException {Thread.sleep(1000);System.out.println(222222222);}
}
/** 输出结果 111111111 * 22222222 * 1002*/
11.Lock
public class ReentrantlockTest {public static void main(String[] args) {ReentrantlockTestA reentrantlockTestA = new ReentrantlockTestA();for (int i = 0; i < 2; i++) {new Thread(new Runnable() {public void run() {try {reentrantlockTestA.testA();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}
}class ReentrantlockTestA {Lock lock = new ReentrantLock();int i;public void testA() throws InterruptedException {lock.lock();try {System.out.println(Thread.currentThread().getName() + ":" + i);Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + ":" + ++i);} finally {lock.unlock();}}
}
/** 输出 * Thread-0:0 * Thread-0:1 * Thread-1:1 * Thread-1:2*/
/** 去除lock后的输出 * Thread-0:0 * Thread-1:0 * Thread-1:1 * Thread-0:1*/
//abc输出
public class demo7 {public static void main(String[] args) {print print = new print();new Thread(new Runnable() {public void run() {for (int i = 1; i <=3; i++) {print.loopA(i);}}}, "A").start();new Thread(new Runnable() {public void run() {for (int i = 1; i <= 3; i++) {print.loopB(i);}}}, "B").start();new Thread(new Runnable() {public void run() {for (int i = 1; i <= 3; i++) {print.loopC(i);}}}, "C").start();}
}// alternate
class print {private int number = 1;private Lock lock = new ReentrantLock();private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();public void loopA(int i) {lock.lock();try {if (number != 1) {condition1.await();}for (int j = 1; j <= 10; j++) {System.out.println(Thread.currentThread().getName() + "\t" + j + "\t" + i);}number = 2;condition2.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void loopB(int i) {lock.lock();try {if (number != 2) {condition2.await();}for (int j = 1; j <= 10; j++) {System.out.println(Thread.currentThread().getName() + "\t" + j + "\t" + i);}number = 3;condition3.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void loopC(int i) {lock.lock();try {if (number != 3) {condition3.await();}for (int j = 1; j <= 10; j++) {System.out.println(Thread.currentThread().getName() + "\t" + j + "\t" + i);}number = 1;condition1.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}
public class ReadAndWriteLock {// 读写互斥// 写写互斥// 读读不互斥public static void main(String[] args) {ReadAndWriteLockA readAndWriteLockA = new ReadAndWriteLockA();new Thread(new Runnable() {public void run() {readAndWriteLockA.testWrite();}}).start();for (int i = 0; i < 100; i++) {new Thread(new Runnable() {public void run() {readAndWriteLockA.testRead();}}).start();}}
}class ReadAndWriteLockA {private int i;ReadWriteLock readWriteLock = new ReentrantReadWriteLock();public void testRead() {readWriteLock.readLock().lock();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i);readWriteLock.readLock().unlock();}public void testWrite() {readWriteLock.writeLock().lock();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("write");this.i = 1;readWriteLock.writeLock().unlock();}
}
12.其他锁语义说明
互斥锁:只能一个进入其他不可以进入,当进入失败,就进入休眠等待休眠结束后才能去尝试访问
自旋锁:只能一个进入其他不可以进入,当进入失败,不停的循环去尝试访问
悲观锁:表锁,原理见redis linux 基础入门
乐观锁:行锁,原理见redis linux 基础入门
13.同步异步,阻塞和非阻塞
同步:我叫你某件事,你没去,我就一直喊
异步:我叫你做某件事后我做别的事情去了,至于你有没有做跟我无关
阻塞:我去做某事,堵车我就一直等着
非阻塞:我去做某事,堵车我就做别的事情,不堵车了再来
14.ConcurrentHashMap
分段锁机制(16段),较hashtable效率盖
15.死锁,活锁和饥饿
死锁:一个需要资源A,一个需要资源B,拿到资源A的人需要拿资源B,不释放A,拿到B的人需要拿资源A,不释放B,这样就都拿不到
活锁:一个需要资源A,一个需要资源B,拿到资源A的人需要拿资源B而拿不到资源B,所以释放A,拿到B的人需要拿资源A,而拿不到资源A,所以释放B,然后发现拿到了B,另一个拿到了A,拿到A的人结果发现拿不到B,拿到B的人结果发现拿不到A,依次循环,就是活锁
饥饿:由于某些原因导致某些线程不能被调用,例如某一个线程的优先级极低,而一直不被调度