解决线程安全问题:
1.synchronized隐式锁
同步代码块
同步方法
2.JDK1.5后
同步锁Lock lock()方方法上锁 必须要,unlock 方法解锁
private Lock lock=new ReentranLock();
public void run(){
while(true){
lock.lock();//上锁
try{
if(tick>0){
try{
Thread.sleep(200);
}catch(InterruptedException e){
}
sysytem.out.println(Thread.currentThread().getName());
}
}finally{
lock.unlock();//释放锁
}
}
}
1,线程交替打印 lock示例:condition控制线程通信
public class TestABCAlternate{
public static void main(String[] args){
AlternateDemo ad=new AlternateDemo();
new Thread(new Runnable(){
public void run(){
for(int i=1;i<=20;i++){
ad.loopA(i);
}
}
},"A").start();
new Thread(new Runnable(){
public void run(){
for(int i=1;i<=20;i++){
ad.loopB(i);
}
}
},"B").start();
new Thread(new Runnable(){
public void run(){
for(int i=1;i<=20;i++){
ad.loopC(i);
}
}
},"C").start();
}
}
class AlternateDemo{
private int number=1;//当前正在执行线程的标记
private Lock lock=new ReentranLock();
private Condition condition1=lock.newCondition();
private Condition condition2=lock.newCondition();
private Condition condition3=lock.newCondition();
public void loopA(){
lock.lock();
try{
if(number!=1){
condition1.await();//等待,,说明不属于1 打印
}
for(int i=1;i<=1;i++){
system.out.println(Thread.currentThread().getName()+ i +totalLoop);
}
number=2;
condition2.signal();//唤醒2
}catch(Exception e){
}finally{
lock.unlock();
}
}
public void loopB(){
lock.lock();
try{
if(number!=1){
condition1.await();//等待,,说明不属于1 打印
}
for(int i=1;i<=1;i++){
system.out.println(Thread.currentThread().getName()+ i +totalLoop);
}
number=3;
condition3.signal();//唤醒2
}catch(Exception e){
}finally{
lock.unlock();
}
}
public void loopC(){
lock.lock();
try{
if(number!=1){
condition1.await();//等待,,说明不属于1 打印
}
for(int i=1;i<=1;i++){
system.out.println(Thread.currentThread().getName()+ i +totalLoop);
}
number=1;
condition1.signal();//唤醒2
}catch(Exception e){
}finally{
lock.unlock();
}
}
}
读写锁:ReadWriteLock 写写/读写 需要互斥
读可以允许多个线程操作
写只能有一个线程操作
class ReadWriteLockDemo{
private int number=0;
private ReadWriteLock lock=new ReentranReadWriteLock();//创建读写锁
//读
public void get(){
lock.readLock.lock();//上锁
try{
system.out.println(number);
}finally{
lock.readLock.unlock();//释放锁
}
}
//写
public void set(int number){
lock.writeLock.lock();
try{
system.out.println(number);
}finally{
lock.writeLock.unlock();//释放锁
}
}
}
1.两个普通同步方法,两个线程,标准打印?one two
2.新增Thread.sleep()给getOne(),打印? one two
3.新增普通同步方法getThread(),打印? one two
4.两个普通同步方法,两个number对象,打印?two one
5.修改getOne()为静态同步方法,一个number对象?two one
6.修改两个方法均为静态同步方法,一个number对象?one two
7.一个静态同步方法,一个非静态同步方法,两个number对象?two one
8.两个静态同步方法,两个number对象?one two
线程八锁的关键:
1.非静态方法的锁默认为this,静态方法的锁为对应的class实例
2.某一个时刻内,只能有一个线程持有锁,无论几个方法。
一、线程池:
提供了一个线程队列,队列中保存着所有等待状态的线程,
避免了创建与销毁开销,提高了响应速度。
二、线程池的体系结构
java.util.concurrent.Executor:负责线程的使用与调度的根接口
ExecutorService子接口:线程池的主要接口
ThreadPoolExecutor 线程池的实现类
ScheduledExecutorService 子接口:负责线程的调度
ScheduledThreadPollExecutor:继承ThreadPoolExecutor,实现ScheduledExecutorService
三、工具类 Executors
ExecutorService newFixedThreadPool();创建固定大小的线程池
ExecutorService newCachedThreadPool();缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
ExecutorService newSingleThreadExecutor();创建单个线程池,线程池中只有一个线程
ScheduledExecutorService newScheduledThreadPool();创建固定大小的线程,可以延迟或定时的执行任务。
public class TestThreadPool{
public static void main(String[] args){
//1.创建线程池 固定大小线程池
ExecutorService pool=Executors.newFixedThreadPool(5);
ThreadPoolDemo ted=new ThreadPoolDemo();
//2.为线程池中的线程分配任务
pool.submit(ted);
//3.关闭线程池
pool.shutdown();
}
class ThreadPoolDemo implements Runnable{
private int i=0;
public void run(){
while(i<100){
i++;
system.out.println("");
}
}
}
Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call()
Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。
必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果
创建执行线程的方式三:
1.实现Callable接口,相较于实现Runnable接口的方式,方式可以有返回值,并且可以抛出异常。
2.执行callable方式,需要FutureTask实现类的支持,用于接收运算结果,FutureTask是Future接口的实现类
class SumTask implements Callable<Long> {
@Override
public Long call() throws Exception {
long sum = 0;
for (int i = 0; i < 9000; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("Start:" + System.nanoTime());
// 将Callable写的任务封装到一个由执行者调度的FutureTask对象
FutureTask<Long> futureTask = new FutureTask<Long>(new SumTask());
// 创建线程池并返回ExecutorService实例
Executor executor=Executors.newSingleThreadExecutor();
//执行任务
executor.execute(futureTask);
//打印输出返回值
System.out.println(futureTask.get());
System.out.println("End:" + System.nanoTime());
}
}
注意点:
避免使用Executors创建线程池,主要是避免使用其中的默认实现,那么我们可以自己直接调用ThreadPoolExecutor的构造函数来自己创建线程池。
在创建的同时,给BlockQueue指定容量就可以了。
private static ExecutorService executor = new ThreadPoolExecutor(10, 10,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue(10));
这种情况下,一旦提交的线程数超过当前可用线程数时,就会抛出java.util.concurrent.RejectedExecutionException,
这是因为当前线程池使用的队列是有边界队列,队列已经满了便无法继续处理新的请求。
但是异常(Exception)总比发生错误(Error)要好
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
浙公网安备 33010602011771号