多线程
一、守护线程
- 守护线程设置必须在start之前;如果在start之后,设定为守护线程,设定无效,且如果线程在执行过程中,将会抛出异常:IllegalThreadStateException
- 守护线程中创建的线程默认是守护线程,可以更改
- Timer是单线程且可以设置为守护线程;GC线程是典型的守护线程
二、Runnable和Callable区别
- Runnable需要实现run方法,Callable需要实现call方法
- run方法没有返回值,call方法需要有返回值
- run方法中的异常只能自己处理,不能抛出;call方法异常可以抛出
- 使用Thread创建线程时,Runnable可以直接作为入参或者使用FutureTask封装;Callable只能使用FutureTask封装,不能直接作为入参
- 使用ExecutorService创建线程时,Runnable可以直接使用execute或submit执行;Callable只能直接被submit执行,不能被execute执行;两者被FutureTask封装后,两者皆可
三、ThreadGroup---具体应用场景未找到
创建线程时可以指定所属线程组,未指定则为当前线程所在线程组。通过线程组可以查看当前线程组内线程的数量和运行状况。
四、线程同步
- sleep和wait区别
- sleep属于Thread静态方法;wait属于Object方法
- sleep不释放锁;wait释放所
- sleep属于静态方法,只能让当前线程进入block状态,所以Thread t=new Thread();t.start();t.sleep(1000);只会让当前线程进入等待状态,对t线程无效
- wait方法必须在synchronized中,否则编译通过,运行时抛出异常
- yield和join方法
- yield方法让当前线程工running状态进入runnable状态,使得其他线程有重新竞争的机会
- join方法实质调用的实wait方法,当相关线程执行结束后自动唤醒。等待调用线程结束后,将继续执行当前线程;调用时,线程处于不活动状态,则不进行阻塞
- 实现线程同步的方法
- 使用synchronized和Lock使得同一时间只有一个线程执行代码块
- 使用volatile保证变量的可见性??
- 使用wait/nofity/notifyAll或者await/signal/signalAll实现多个线程间同步
- 使用CountDownLatch,CyclicBarrier和Semaphore实现多线程同步??
五、线程安全
- 三大概念:可见性,原子性,有序性
- synchronized和Lock(ReentrantLock ReentrantReadWriteLock)区别
- Lock可以实现synchronized效果,lock.lock()--进入锁;lock.unlock()--释放锁
- Condition c=lock.newCondition() c.await()和wait同效果--释放当前保持的锁,c.signal()和notify()同效果,signalAll和notifyAll相同----必须是同一个Condition
- lock.tryLock()尝试获取锁,获取则返回true,未获取返回false;
- lock.writeLock.lock()和lock.readLock.lock();读读锁不互斥,两个线程可以同时获取读锁;写写锁和读写锁互斥,必须等锁释放才能获取
- 线程安全方法
- 使用ThreadLocal。使不同线程访问不同资源。
- volatile保证变量的可见性,以及一定程度的有序性
- 使用Atomic类进行原子性操作
- 使用synchronized和Lock保证原子性和互斥性
六、线程间通信
- volatile,while轮询,synchronized和Lock共享内存
- 使用BlockingQueue阻塞队列
- wait/notify/notifyAll join await/signal/signalAll线程间通知
- CountDownLatch,CyclicBerrier和Semaphore
- Callable接口返回数据
- 管道通信 java.io.PipedInputStream PipedOutStream
七、线程池
八、CountDownLatch,CyclicBarrier和Semaphore
- CountDownLatch实现类似计数器功能。构造函数CountDownLatch(int i);常用方法:await()方法--挂起当前线程;countDown()方法--计数器减一,直到减为0,所有挂起线程开始执行
- CyclicBarrier实现线程等待。构造函数CyclicBarrier(int parties);常用方法:await()--挂起线程,直到parties个数线程同时挂起,才开始执行。 构造函数CyclicBarrier(int parties,Runnable barrierAction);挂起线程数为parties时,使用一个线程执行barrierAction,执行结束之后,所有挂起线程开始执行;如果barrierAction线程发生阻塞,则所有线程一直处于挂起状态
- Semaphore控制线程并发数。构造函数Semaphore(int permits);常用方法:acquire(),acquire(int permits)--获取单个或设定数量的许可,未获取,则一直等到; release(),release(int permits);释放许可 tryAcquire(),tryAcquire(int permits)--尝试获取许可,如果获取返回true,否则返回false
- CountDownLatch和CyclicBarrier区别
- CountDownLatch可以代码控制重新开启线程的时间;CyclicBarrier只能自动执行
- ConntDownLatch不可以重用,countDown之后await失效;CyclicBarrier执行结束后可以重新使用
- CountDownLatch理论是可以控制任何数量线程挂起,一般只控制一个,一般一个线程等待,等待其他线程执行结束;CyclicBarrier控制多个线程在某个状态等待,直到所有都到达这个状态,开始执行
- Semaphore类似于锁,可以控制并发线程的数量
九、其他
- new Thread(new Runnable(){public void run(){System.out.println("1111");}}){public void run(){System.out.println("2222");}} 既重写了Thread的run方法,又传入了Runnable实现,最后会执行哪个run方法?
-
- 涉及匿名内部类调用父类构造函数;
- 重写Thread的run方法可定执行,Runnable方法是否执行,根据run方法是否调用super.run();如果调用了,则执行。
- super.run();System.out.println("2222"); 控制台结果:1111 2222
- System.out.pringln(“2222”);super.run();控制台结果:2222 1111
- System.out.pringln(“2222”); 控制台结果:2222
2、查看当前线程是否持有某对象的锁。Thread.holdsLock(obj);和sleep类似,只能查看当前线程是否持有某对象的锁,即使是使用其他线程对象执行此方法
3、wait/notify/notifyAll+synchronized+信号量+while 信号量保证notify提前执行也可以正确执行;while保证假唤醒时可以继续判断 不要在字符串常量和全局变量使用wait

浙公网安备 33010602011771号