简介
1.JUC简介
在Java中,线程部分是一个重点。JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包,JDK 1.5开始出现的。
2.线程与进程
1.进程与线程
进程是指处于运行过程中的程序,并且具有一定的独立功能。进程是系统进行资源分配和调度的一个单位。当程序进入内存运行时,即为线程。简而言之,进程是一个程序,或者是一个程序集合。一个进程包含至少一个或多个线程。
java中默认开启的线程:main线程和gc线程
java开启多线程的方法:Thread,Runnable,Callable
2.并发与并行:
并发:多个线程操作同一个资源
并行:多个线程同时执行,线程池
本质问题:CPU的资源得以充分利用
3.锁
java中有两种常用的锁机制,一种是synchronized,另一种是基于juc实现,synchronized是java底层支持的,而concurrent包则是jdk实现。
1.重量级锁Synchronized
在JDK1.5之前都是使用synchronized关键字保证同步的,它可以把任意一个非NULL的对象当作锁。作用于方法时,锁住的是对象的实例(this);当作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在永久带PermGen(jdk1.8则是metaspace),永久带是全局共享的,因此静态方法锁相当于类的一个全局锁,会锁所有调用该方法的线程;synchronized作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。Synchronized是非公平锁。
2.Lock
Lock是一个接口。主要有如下关系:
3.二者区别
Lock与synchronized有以下区别:
Lock是一个接口,而synchronized是关键字。
synchronized会自动释放锁,而Lock必须手动释放锁。如果不释放会产生死锁问题。
Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。
通过Lock可以知道线程有没有拿到锁,而synchronized不能。
Lock能提高多个线程读操作的效率。
synchronized能锁住类、方法和代码块,而Lock是块范围内的。
synchronized适合少量的代码同步问题,Lock适合锁大量的同步代码。
synchronized是可重入锁,不可以中断,非公平;Lock是可重入锁。
4.生产者消费者
1.Synchronized实现
创建资源类:
class Data{
private int num = 0;
/**
* @description 生产者 数量+1
*/
public synchronized void incre() throws InterruptedException {
while (num!=0){
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"====>"+num);
this.notifyAll();
}
/**
* @description 消费者 数量-1
*/
public synchronized void decr() throws InterruptedException {
while (num==0){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"====>"+num);
this.notifyAll();
}
}
注:用while做条件判断:因为if判断会存在虚假唤醒,jdk官方推荐使用while
创建操作main函数
public class ProdConsumSyncTest {
public static void main(String[] args) {
Data data = new Data();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.incre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"A").start();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"B").start();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.incre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"C").start();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"D").start();
}
}
2.使用Lock实现
public class ProdConsumLockTest {
public static void main(String[] args) {
Data1 data = new Data1();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"A").start();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"B").start();
new Thread(
()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"C").start();
new Thread(
()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
,"D").start();
}
}
class Data1{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//condition.await(); // 等待
// condition.signalAll(); // 唤醒全部
// +1
public void increment() throws InterruptedException {
lock.lock();
try {
// 业务代码
while (number!=0){ //0 // 等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
// 通知其他线程,我+1完毕了
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public synchronized void decrement() throws InterruptedException {
lock.lock();
try {
while (number==0){
// 1 // 等待
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
// 通知其他线程,我-1完毕了
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
参考:狂神说java