• java的多线程juc


    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() + " " + j + " " + 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() + " " + j + " " + 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() + " " + j + " " + 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,依次循环,就是活锁

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

  • 相关阅读:
    tcpdump分析tcp连接的建立、传输和关闭
    链表排序:冒泡和快排
    linux文件IO操作篇 (一) 非缓冲文件
    linux文件操作篇 (四) 目录操作
    linux文件操作篇 (三) 文件状态和操作属性
    linux文件操作篇 (二) 打开和关闭文件
    linux文件操作篇 (一)文件属性与权限
    linux编程(三)多线程
    linux编程(二)进程
    linux编程(一)文件IO 目录
  • 原文地址:https://www.cnblogs.com/gg128/p/9384016.html
Copyright © 2020-2023  润新知