java的多线程juc

时间:2023-02-13 13:53:38

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 {

	@Override
	public 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 { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(1111); } } class DaemonTestB implements Runnable { @Override public 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 { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello thread"); } } class ThreadTestB implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello runnable"); } } class ThreadTestC implements Callable<String> { @Override public 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);// 4001 WaitTest 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{ @Override public void run() { System.out.println(1); Thread.yield(); System.out.println(2); } } class B implements Runnable{ @Override public 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 { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello thread"); } } class ThreadTestB implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello runnable"); } } class ThreadTestC implements Callable<String> { @Override public 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 queue
                r = workQueue.poll();
            else if (poolSize > corePoolSize || allowCoreThreadTimeOut) //如果线程数大于核心池大小或者允许为核心池线程设置空闲时间,
                //则通过poll取任务,若等待一定的时间取不到任务,则返回null
                r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
            else
                r = workQueue.take();
            if (r != null)
                return r;
            if (workerCanExit()) {    //如果没取到任务,即r为null,则判断当前的worker是否可以退出
                if (runState >= SHUTDOWN) // Wake up others
                    interruptIdleWorkers();   //中断处于空闲状态的worker
                return 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 {
		@Override
		public 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)的效率是非常的高的,验证共享机制
	@Test
	public  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;
	@Override
	public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		flag2=true;
		System.out.println("flag=true");
	}
}
public class VolatileTest2 {
	//死循环输出,因为while(true)的效率是非常的高的
	@Test
	public  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;
	@Override
	public 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; @Override public 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);
	@Override
	public void run(){
		System.out.println(Thread.currentThread().getName()+":"+test());
	}
	//atomicInteger
	public  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() {
				
				@Override
				public void run() {
					int expectedValue = cas.get();
					//会争抢锁
					//假如在这里加一个线程延时那么会基本上是false
					boolean 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,依次循环,就是活锁

饥饿:由于某些原因导致某些线程不能被调用,例如某一个线程的优先级极低,而一直不被调度