JUC重点梳理
- 1 JUC
- 1.1 培训 教育
- 思维方式+认知+方法论
- 1.2 是什么
- 1.3 能干嘛
- 1.4 去哪下
- 1.5 怎么玩+永远的HelloWorld
- WWH
- juc是什么:java.util.concurrent
- 2 并发?并行?
- 3 进程,线程
3.1 QQ.exe WinWord.Exe 163Music.exe
3.2 word WinWord.Exe - 4 int Integer(i++) AtomicInteger
- 5 java.util.concurrent
-
java.util.concurrent.atomic
-
java.util.concurrent.locks
- 6 Lambda Express
- 7 List list
Callable接口
官方API解读
@FunctionalInterface
public interface Callable返回结果并可能引发异常的任务。 实现者定义一个没有参数的单一方法,称为call 。
Callable接口类似于Runnable ,因为它们都是为其实例可能由另一个线程执行的类设计的。 然而,Runnable不返回结果,也不能抛出被检查的异常。
该Executors类包含的实用方法,从其他普通形式转换为Callable类。
代码演示
class Mythread implements Callable {
@Override
public Object call(){//可以定义为Integer型
System.out.println("come in call method()");
return 20190813;
}
}
main方法测试
public class HwCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Mythread());
new Thread(futureTask,"A").start();
Integer result = futureTask.get();//获取call返回值
System.out.println(result);
}
}
Condition接口
官方API解读
-
public interface ConditionCondition因素出Object监视器方法( wait , notify和notifyAll )成不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果Lock个实现。 Lock替换synchronized方法和语句的使用, Condition取代了对象监视器方法的使用。
-
条件(也称为条件队列或条件变量 )为一个线程暂停执行(“等待”)提供了一种方法,直到另一个线程通知某些状态现在可能为真。 因为访问此共享状态信息发生在不同的线程中,所以它必须被保护,因此某种形式的锁与该条件相关联。 等待条件的关键属性是它原子地释放相关的锁并挂起当前线程,就像Object.wait 。
-
一个Condition实例本质上绑定到一个锁。 要获得特定Condition实例的Condition实例,请使用其newCondition()方法。
-
例如,假设我们有一个有限的缓冲区,它支持put和take方法。 如果在一个空的缓冲区尝试一个take ,则线程将阻塞直到一个项目可用; 如果put试图在一个完整的缓冲区,那么线程将阻塞,直到空间变得可用。 我们希望在单独的等待集中等待put线程和take线程,以便我们可以在缓冲区中的项目或空间可用的时候使用仅通知单个线程的优化。 这可以使用两个Condition实例来实现。
condition案例:多线程之间按顺序调用,实现A->B->C
- 三个线程启动,要求如下:
- AA打印5次,BB打印10次,CC打印15次
- 接着
- AA打印5次,BB打印10次,CC打印15次
- 来10轮
资源类代码
class ShareData {
private int number = 1;//A:1 B:2 C:3
private Lock lock = new ReentrantLock();//重进入锁
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5() throws InterruptedException {
lock.lock();
try {
//用while判断,不能用if
while (number != 1)
c1.await();
//干活
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 2;
c2.signal();
} finally {
lock.unlock();
}
}
public void print10() throws InterruptedException {
lock.lock();
try {
//用while判断,不能用if
while (number != 2)
c2.await();
//干活
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 3;
c3.signal();
} finally {
lock.unlock();
}
}
public void print15() throws InterruptedException {
lock.lock();
try {
//用while判断,不能用if
while (number != 3)
c3.await();
//干活
for (int i = 1; i <= 15; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 1;
c1.signal();
} finally {
lock.unlock();
}
}
}
启用线程测试
public class HwCondition {
public static void main(String[] args) {
ShareData shareData = new ShareData();
//启动多线程
new Thread(() -> {
for (int i = 1; i <= 10; i++) {//循环10轮
try {
shareData.print5();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
shareData.print10();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
shareData.print15();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
}
}
condition接口的生产消费任务演示
任务题目:现在两个线程,可以操作初始值为零的一个变量,
-
实现一个线程对该变量加1,一个线程对该变量减1,
-
实现交替,来10轮,变量初始值为零。
-
1 高聚低合前提下,线程操作资源类
-
2 判断/干活/通知
-
3 防止虚假唤醒
-
知识小总结 = 多线程编程套路+while判断+新版写法
public class HwProdConsumer { public static void main(String[] args) { Aircondition aircondition = new Aircondition(); //生产线程 new Thread(() -> { for (int i = 1; i <= 10; i++) { try { Thread.sleep(200); aircondition.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A1").start(); //消费线程 new Thread(() -> { for (int i = 1; i <= 10; i++) { try { Thread.sleep(300); aircondition.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B1").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { Thread.sleep(200); aircondition.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A2").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { Thread.sleep(400); aircondition.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B2").start(); } } class Aircondition { private int number = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void increment() throws InterruptedException { lock.lock(); try { //while判断,如果用if则会出bug while (number != 0) { condition.await(); } //生产商品 number++; System.out.println(Thread.currentThread().getName() + "\t剩余商品数量" + number); //通知其他线程 condition.signalAll(); } finally { lock.unlock(); } } public void decrement() throws InterruptedException { lock.lock(); try { //while判断,如果用if则会出bug while (number == 0) { condition.await(); } //消费商品 number--; System.out.println(Thread.currentThread().getName() + "\t剩余商品数量" + number); //通知其他线程 condition.signalAll(); } finally { lock.unlock(); } } }
注意一定要用while判断语句,用if判断则失效
旧版本线程资源类代码
/*public synchronized void increment()throws Exception
{
//1 判断
while (number != 0)
{
//AAA CCC
this.wait();
}
//2 干活
number++;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//3 通知
this.notifyAll();
}
public synchronized void decrement()throws Exception
{
//1 判断
while(number == 0)
{
this.wait();
}
//2 干活
number--;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//3 通知
this.notifyAll();
}*/