建设部精神文明建设网站,宜昌网站制作,15年做那些网站能致富,如何做 网站的seo目录
一、什么是JUC
1、JUC概述 2、进程与线程
3、线程的状态
4、wait/sleep 的区别
5、并发与并行
6、管程
7、用户线程和守护线程
二、Lock接口
1、Synchronized
使用synchronized实现售票案例
使用synchronized实现增减变量操作
2、什么是 Lock
买票例子使用lo…目录
一、什么是JUC
1、JUC概述 2、进程与线程
3、线程的状态
4、wait/sleep 的区别
5、并发与并行
6、管程
7、用户线程和守护线程
二、Lock接口
1、Synchronized
使用synchronized实现售票案例
使用synchronized实现增减变量操作
2、什么是 Lock
买票例子使用lock实现
增减变量操作使用lock实现
3、newCondition
增减变量操作使用Condition实现
线程定制化执行
4、ReentrantLock
5、ReadWriteLock 一、什么是JUC
1、JUC概述
JUC 就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包JDK 1.5 开始出现的。 2、进程与线程 进程Process 是计算机中的程序关于某数据集合上的一次运行活动是系统进行资源分配和调度的基本单位是操作系统结构的基础。 在当代面向线程设计的计算机结构中进程是线程的容器。程序是指令、数据及其组织形式的描述进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动是系统进行资源分配和调度的基本单位是操作系统结构的基础。程序是指令、数据及其组织形式的描述进程是程序的实体。 线程thread 是操作系统能够进行运算调度的最小单位。它被包含在进程之中是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流一个进程中可以并发多个线程每条线程并行执行不同的任务。 即 进程指在系统中正在运行的一个应用程序程序一旦运行就是进程进程— —资源分配的最小单位。 线程系统分配处理器时间资源的基本单元或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。 3、线程的状态 public enum State {/*** Thread state for a thread which has not yet started.*/NEW, // 新建/*** Thread state for a runnable thread. A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.*/RUNNABLE, // 运行时/*** Thread state for a thread blocked waiting for a monitor lock.* A thread in the blocked state is waiting for a monitor lock* to enter a synchronized block/method or* reenter a synchronized block/method after calling* {link Object#wait() Object.wait}.*/BLOCKED, // 阻塞/*** Thread state for a waiting thread.* A thread is in the waiting state due to calling one of the* following methods:* ul* li{link Object#wait() Object.wait} with no timeout/li* li{link #join() Thread.join} with no timeout/li* li{link LockSupport#park() LockSupport.park}/li* /ul** pA thread in the waiting state is waiting for another thread to* perform a particular action.** For example, a thread that has called ttObject.wait()/tt* on an object is waiting for another thread to call* ttObject.notify()/tt or ttObject.notifyAll()/tt on* that object. A thread that has called ttThread.join()/tt* is waiting for a specified thread to terminate.*/WAITING, //等待/*** Thread state for a waiting thread with a specified waiting time.* A thread is in the timed waiting state due to calling one of* the following methods with a specified positive waiting time:* ul* li{link #sleep Thread.sleep}/li* li{link Object#wait(long) Object.wait} with timeout/li* li{link #join(long) Thread.join} with timeout/li* li{link LockSupport#parkNanos LockSupport.parkNanos}/li* li{link LockSupport#parkUntil LockSupport.parkUntil}/li* /ul*/TIMED_WAITING, // 过时不候/*** Thread state for a terminated thread.* The thread has completed execution.*/TERMINATED; //终结} 4、wait/sleep 的区别 1sleep 是 Thread 的静态方法wait 是 Object 的方法任何对象实例都能调用。 2sleep 不会释放锁它也不需要占用锁。wait 会释放锁但调用它的前提是当前线程占有锁(即代码要在 synchronized 中)。 3它们都可以被 interrupted 方法中断。 5、并发与并行 串行表示所有任务都一一按先后顺序进行 并发:并发是指两个或多个事件在同一时间间隔发生。 例子春运抢票 电商秒杀... 并行:并行是指两个或者多个事件在同一时刻发生。 例子泡方便面电水壶烧水一边撕调料倒入桶中 6、管程 管程(monitor) 是保证了同一时刻只有一个进程在管程内活动 , 即管程内定义的操作在同一时刻只被一个进程调用( 由编译器实现 ). 但是这样并不能保证进程以设计的顺序执行 JVM 中同步是基于进入和退出管程 (monitor) 对象实现的每个对象都会有一个管程(monitor)对象管程 (monitor) 会随着 java 对象一同创建和销毁 执行线程首先要持有管程对象然后才能执行方法当方法完成之后会释放管程方法在执行时候会持有管程其他线程无法再获取同一个管程 7、用户线程和守护线程 用户线程 : 平时用到的普通线程 , 自定义线程 守护线程 : 运行在后台 , 是一种特殊的线程 , 比如垃圾回收 当主线程结束后 , 用户线程还在运行 ,JVM 存活 如果没有用户线程 , 都是守护线程 ,JVM 结束 二、Lock接口
1、Synchronized synchronized 是 Java 中的关键字是一种同步锁。它修饰的对象有以下几种 修饰一个代码块被修饰的代码块称为同步语句块其作用的范围是大括号{}括起来的代码作用的对象是调用这个代码块的对象 修饰一个方法被修饰的方法称为同步方法其作用的范围是整个方法作用的对象是调用这个方法的对象 修改一个静态的方法其作用的范围是整个静态方法作用的对象是这个类的所有对象 修改一个类其作用的范围是 synchronized 后面括号括起来的部分作用主的对象是这个类的所有对象 虽然可以使用 synchronized 来定义方法但 synchronized 并不属于方法定义的一部分因此synchronized 关键字不能被继承。如果在父类中的某个方法使用了 synchronized 关键字而在子类中覆盖了这个方法在子类中的这个方法默认情况下并不是同步的而必须显式地在子类的这个方法中加上synchronized 关键字才可以。当然还可以在子类方法中调用父类中相应的方法这样虽然子类中的方法不是同步的但子类调用了父类的同步方法因此子类的方法也就相当于同步了。 使用synchronized实现售票案例
//第一步 创建资源类定义属性和和操作方法
class Ticket {//票数private int number 30;//操作方法卖票public synchronized void sale() {//判断是否有票if(number 0) {System.out.println(Thread.currentThread().getName() : 卖出(number--) 剩下number);}}
}public class SaleTicket {//第二步 创建多个线程调用资源类的操作方法public static void main(String[] args) {//创建Ticket对象Ticket ticket new Ticket();//创建三个线程new Thread(new Runnable() {Overridepublic void run() {//调用卖票方法for (int i 0; i 40; i) {ticket.sale();}}},AA).start();new Thread(new Runnable() {Overridepublic void run() {for(int i 0; i 40; i ) {ticket.sale();}}},DD);new Thread(new Runnable() {Overridepublic void run() {//调用卖票方法for (int i 0; i 40; i) {ticket.sale();}}},BB).start();new Thread(new Runnable() {Overridepublic void run() {//调用卖票方法for (int i 0; i 40; i) {ticket.sale();}}},CC).start();}
} 使用synchronized实现增减变量操作
当变量为0是线程A、C将其1当变量为1时B、D线程将其-1
//第一步 创建资源类定义属性和操作方法
class Share {//初始值private int number 0;//1的方法public synchronized void incr() throws InterruptedException {//第二步 判断 干活 通知while(number ! 0) { //判断number值是否是0如果不是0等待this.wait(); //在哪里睡就在哪里醒}//如果number值是0就1操作number;System.out.println(Thread.currentThread().getName() :: number);//通知其他线程this.notifyAll();}//-1的方法public synchronized void decr() throws InterruptedException {//判断while(number ! 1) {this.wait();}//干活number--;System.out.println(Thread.currentThread().getName() :: number);//通知其他线程this.notifyAll();}
}public class ThreadDemo1 {//第三步 创建多个线程调用资源类的操作方法public static void main(String[] args) {Share share new Share();//创建线程new Thread(()-{for (int i 1; i 10; i) {try {share.incr(); //1} catch (InterruptedException e) {e.printStackTrace();}}},AA).start();new Thread(()-{for (int i 1; i 10; i) {try {share.decr(); //-1} catch (InterruptedException e) {e.printStackTrace();}}},BB).start();new Thread(()-{for (int i 1; i 10; i) {try {share.incr(); //1} catch (InterruptedException e) {e.printStackTrace();}}},CC).start();new Thread(()-{for (int i 1; i 10; i) {try {share.decr(); //-1} catch (InterruptedException e) {e.printStackTrace();}}},DD).start();}
}如果一个代码块被 synchronized 修饰了当一个线程获取了对应的锁并执行该代码块时其他线程便只能一直等待等待获取锁的线程释放锁而这里获取锁的线程释放锁只会有两种情况 1获取锁的线程执行完了该代码块然后线程释放对锁的占有 2线程执行发生异常此时 JVM 会让线程自动释放锁。 那么如果这个获取锁的线程由于要等待 IO 或者其他原因比如调用 sleep 方法被阻塞了但是又没有释放锁其他线程便只能干巴巴地等待试想一下这多么影响程序执行效率。 因此就需要有一种机制可以不让等待的线程一直无期限地等待下去比如只等待一定的时间或者能够响应中断通过 Lock 就可以办到。 2、什么是 Lock Lock 锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构可能具有非常不同的属性并且可能支持多个关联的条件对象。Lock 提供了比 synchronized 更多的功能。 Lock 与的 Synchronized 区别 Lock 不是 Java 语言内置的synchronized 是 Java 语言的关键字因此是内置特性。Lock 是一个类通过这个类可以实现同步访问 Lock 和 synchronized 有一点非常大的不同采用 synchronized 不需要用户去手动释放锁当 synchronized 方法或者 synchronized 代码块执行完之后系统会自动让线程释放对锁的占用而 Lock 则必须要用户去手动释放锁如果没有主动释放锁就有可能导致出现死锁现象。 public interface Lock {void lock();void lockInterruptibly() throws InterruptedException;boolean tryLock();boolean tryLock(long time, TimeUnit unit) throws InterruptedException;void unlock();Condition newCondition();
} lock()方法是平常使用得最多的一个方法就是用来获取锁。如果锁已被其他线程获取则进行等待。 采用 Lock必须主动去释放锁并且在发生异常时不会自动释放锁。因此一般来说使用 Lock 必须在 try{}catch{}块中进行并且将释放锁的操作放在finally 块中进行以保证锁一定被被释放防止死锁的发生。通常使用 Lock 来进行同步的话是以下面这种形式去使用的 lock.lock();try{//处理任务}catch(Exception ex){}finally{lock.unlock(); //释放锁} 买票例子使用lock实现 //第一步 创建资源类定义属性和和操作方法
class LTicket {//票数量private int number 30;//创建可重入锁private final ReentrantLock lock new ReentrantLock(true);//卖票方法public void sale() {//上锁lock.lock();try {//判断是否有票if(number 0) {System.out.println(Thread.currentThread().getName() 卖出(number--) 剩余number);}} finally {//解锁lock.unlock();}}
}public class LSaleTicket {//第二步 创建多个线程调用资源类的操作方法//创建三个线程public static void main(String[] args) {LTicket ticket new LTicket();new Thread(()- {for (int i 0; i 40; i) {ticket.sale();}},AA).start();new Thread(() - {for(int i 0; i 40; i ) {ticket.sale();}}, DD);new Thread(()- {for (int i 0; i 40; i) {ticket.sale();}},BB).start();new Thread(()- {for (int i 0; i 40; i) {ticket.sale();}},CC).start();}
}增减变量操作使用lock实现 //第一步 创建资源类定义属性和操作方法
class Share {private int number 0;//创建Lockprivate Lock lock new ReentrantLock();private Condition condition lock.newCondition();//1public void incr() throws InterruptedException {//上锁lock.lock();try {//判断while (number ! 0) {condition.await();}//干活number;System.out.println(Thread.currentThread().getName() :: number);//通知condition.signalAll();}finally {//解锁lock.unlock();}}//-1public void decr() throws InterruptedException {lock.lock();try {while(number ! 1) {condition.await();}number--;System.out.println(Thread.currentThread().getName() :: number);condition.signalAll();}finally {lock.unlock();}}
}public class ThreadDemo2 {public static void main(String[] args) {Share share new Share();new Thread(()-{for (int i 1; i 10; i) {try {share.incr();} catch (InterruptedException e) {e.printStackTrace();}}},AA).start();new Thread(()-{for (int i 1; i 10; i) {try {share.decr();} catch (InterruptedException e) {e.printStackTrace();}}},BB).start();new Thread(()-{for (int i 1; i 10; i) {try {share.incr();} catch (InterruptedException e) {e.printStackTrace();}}},CC).start();new Thread(()-{for (int i 1; i 10; i) {try {share.decr();} catch (InterruptedException e) {e.printStackTrace();}}},DD).start();}} 3、newCondition 关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式 Lock 锁的 newContition()方法返回 Condition 对象Condition 类也可以实现等待/通知模式。 用 notify()通知时JVM 会随机唤醒某个等待的线程 使用 Condition 类可以进行选择性通知 Condition 比较常用的两个方法 • await()会使当前线程等待,同时会释放锁,当其他线程调用 signal()时,线程会重新获得锁并继续执行。 • signal()用于唤醒一个等待的线程。 注意在调用 Condition 的 await()/signal()方法前也需要线程持有相关的 Lock 锁调用 await()后线程会释放这个锁在 singal()调用后会从当前 Condition 对象的等待队列中唤醒 一个线程唤醒的线程尝试获得锁 一旦获得锁成功就继续执行。 增减变量操作使用Condition实现
//第一步 创建资源类定义属性和操作方法
class Share {private int number 0;//创建Lockprivate Lock lock new ReentrantLock();private Condition condition lock.newCondition();//1public void incr() throws InterruptedException {//上锁lock.lock();try {//判断while (number ! 0) {condition.await();}//干活number;System.out.println(Thread.currentThread().getName() :: number);//通知condition.signalAll();}finally {//解锁lock.unlock();}}//-1public void decr() throws InterruptedException {lock.lock();try {while(number ! 1) {condition.await();}number--;System.out.println(Thread.currentThread().getName() :: number);condition.signalAll();}finally {lock.unlock();}}
}public class ThreadDemo2 {public static void main(String[] args) {Share share new Share();new Thread(()-{for (int i 1; i 10; i) {try {share.incr();} catch (InterruptedException e) {e.printStackTrace();}}},AA).start();new Thread(()-{for (int i 1; i 10; i) {try {share.decr();} catch (InterruptedException e) {e.printStackTrace();}}},BB).start();new Thread(()-{for (int i 1; i 10; i) {try {share.incr();} catch (InterruptedException e) {e.printStackTrace();}}},CC).start();new Thread(()-{for (int i 1; i 10; i) {try {share.decr();} catch (InterruptedException e) {e.printStackTrace();}}},DD).start();}}线程定制化执行
让线程按顺序执行例子
当flag为1时A线程打印五次
当flag为2时B线程打印十次
当flag为3时C线程打印十五次
按顺序打印。
//第一步 创建资源类
class ShareResource {//定义标志位private int flag 1; // 1 AA 2 BB 3 CC//创建Lock锁private Lock lock new ReentrantLock();//创建三个conditionprivate Condition c1 lock.newCondition();private Condition c2 lock.newCondition();private Condition c3 lock.newCondition();//打印5次参数第几轮public void print5(int loop) throws InterruptedException {//上锁lock.lock();try {//判断while(flag ! 1) {//等待c1.await();}//干活for (int i 1; i 5; i) {System.out.println(Thread.currentThread().getName() :: i 轮数loop);}//通知flag 2; //修改标志位 2c2.signal(); //通知BB线程}finally {//释放锁lock.unlock();}}//打印10次参数第几轮public void print10(int loop) throws InterruptedException {lock.lock();try {while(flag ! 2) {c2.await();}for (int i 1; i 10; i) {System.out.println(Thread.currentThread().getName() :: i 轮数loop);}//修改标志位flag 3;//通知CC线程c3.signal();}finally {lock.unlock();}}//打印15次参数第几轮public void print15(int loop) throws InterruptedException {lock.lock();try {while(flag ! 3) {c3.await();}for (int i 1; i 15; i) {System.out.println(Thread.currentThread().getName() :: i 轮数loop);}//修改标志位flag 1;//通知AA线程c1.signal();}finally {lock.unlock();}}
}public class ThreadDemo3 {public static void main(String[] args) {ShareResource shareResource new ShareResource();new Thread(()-{for (int i 1; i 10; i) {try {shareResource.print5(i);} catch (InterruptedException e) {e.printStackTrace();}}},AA).start();new Thread(()-{for (int i 1; i 10; i) {try {shareResource.print10(i);} catch (InterruptedException e) {e.printStackTrace();}}},BB).start();new Thread(()-{for (int i 1; i 10; i) {try {shareResource.print15(i);} catch (InterruptedException e) {e.printStackTrace();}}},CC).start();}
}4、ReentrantLock ReentrantLock意思是“可重入锁”关于可重入锁的概念将在后面讲述。 ReentrantLock 是唯一实现了 Lock 接口的类并且 ReentrantLock 提供了更多的方法。下面通过一些实例看具体看一下如何使用。 public class Test {private ArrayListInteger arrayList new ArrayListInteger();public static void main(String[] args) {final Test test new Test();new Thread() {public void run() {test.insert(Thread.currentThread());};}.start();new Thread() {public void run() {test.insert(Thread.currentThread());};}.start();}public void insert(Thread thread) {ReentrantLock lock new ReentrantLock(); //注意这个地方lock.lock();try {System.out.println(thread.getName() 得到了锁);for (int i 0; i 5; i) {arrayList.add(i);}} catch (Exception e) {
// TODO: handle exception} finally {System.out.println(thread.getName() 释放了锁);lock.unlock();}}
} 5、ReadWriteLock ReadWriteLock 也是一个接口在它里面只定义了两个方法 public interface ReadWriteLock {/*** Returns the lock used for reading.** return the lock used for reading.*/Lock readLock();/*** Returns the lock used for writing.** return the lock used for writing.*/Lock writeLock();
} 一个用来获取读锁一个用来获取写锁。也就是说将文件的读写操作分开分成 2 个锁来分配给线程从而使得多个线程可以同时进行读操作。下面的 ReentrantReadWriteLock 实现了 ReadWriteLock 接口。 ReentrantReadWriteLock 里面提供了很多丰富的方法不过最主要的有两个方法readLock()和 writeLock()用来获取读锁和写锁。 下面通过几个例子来看一下 ReentrantReadWriteLock 具体用法。 假如有多个线程要同时进行读操作的话先看一下 synchronized 达到的效果 public class Test {private ReentrantReadWriteLock rwl newReentrantReadWriteLock();public static void main(String[] args) {final Test test new Test();new Thread() {public void run() {test.get(Thread.currentThread());};}.start();new Thread() {public void run() {test.get(Thread.currentThread());};}.start();}public synchronized void get(Thread thread) {long start System.currentTimeMillis();while (System.currentTimeMillis() - start 1) {System.out.println(thread.getName() 正在进行读操作);}System.out.println(thread.getName() 读操作完毕);}
} 而改成用读写锁的话
public class Test {private ReentrantReadWriteLock rwl newReentrantReadWriteLock();public static void main(String[] args) {final Test test new Test();new Thread() {public void run() {test.get(Thread.currentThread());};}.start();new Thread() {public void run() {test.get(Thread.currentThread());};}.start();}public void get(Thread thread) {rwl.readLock().lock();try {long start System.currentTimeMillis();while (System.currentTimeMillis() - start 1) {System.out.println(thread.getName() 正在进行读操作);}System.out.println(thread.getName() 读操作完毕);} finally {rwl.readLock().unlock();}}
} 说明 thread1 和 thread2 在同时进行读操作。这样就大大提升了读操作的效率。 注意: • 如果有一个线程已经占用了读锁则此时其他线程如果要申请写锁则申请写锁的线程会一直等待释放读锁。 • 如果有一个线程已经占用了写锁则此时其他线程如果申请写锁或者读锁则申请的线程会一直等待释放写锁。 Lock 和 synchronized 有以下几点不同 Lock 是一个接口而 synchronized 是 Java 中的关键字synchronized 是内置的语言实现 synchronized 在发生异常时会自动释放线程占有的锁因此不会导致死锁现象发生而 Lock 在发生异常时如果没有主动通过 unLock()去释放锁则很可能造成死锁现象因此使用 Lock 时需要在 finally 块中释放锁 Lock 可以让等待锁的线程响应中断而 synchronized 却不行使用synchronized 时等待的线程会一直等待下去不能够响应中断通过 Lock 可以知道有没有成功获取锁而synchronized 却无法办到。 Lock 可以提高多个线程进行读操作的效率。 在性能上来说如果竞争资源不激烈两者的性能是差不多的而当竞争资源非常激烈时即有大量线程同时竞争此时 Lock 的性能要远远优于synchronized。