P3141_7_2_14_匿名内部类方式实现线程的创建
P3171_7_3_03_线程安全问题举例解析(比如,为何三个线程都抢到第100张票(抢票和票–,执行有时间差,在这个差里,其他两个线程都抢票了,但是第一个抢票的线程还未到–,有点像脏读的意思。为何会有负的:第一个出来后判断条件不符合,正常已不进去,但方法的局部代码块里还有行程在待醒,比如第二第三个线程睡醒了,又去抢票,又–,那么,就有负了(而且,三个线程,最多最蛋疼最坏情况也就是最终票数会到-1了)))
327线程间通信
332线程池
https://www.bilibili.com/video/av54059237/?p=314
Java线程的5种状态及切换
https://www.cnblogs.com/hejing-swust/p/8038263.html
1. 新建(NEW):新创建了一个线程对象。
2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
java中创建线程的三种方法以及区别
https://www.cnblogs.com/3s540/p/7172146.html
java中线程同步的几种方法
https://blog.csdn.net/scgyus/article/details/79499650
方法一:
使用synchronized关键字 (修饰方法,就叫同步方法)
方法二:
wait()和notify()
sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出抢到的cpu的执行权,给其他线程抢,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,(如果有锁的话),线程不会释放对象锁(只是“睡眠”,不放锁,而且还定时,时间到了就恢复运行)(那其他抢到执行权的线程,却无法操作那个有锁的对象(比如runnableImpl))。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。(放了锁,滚回大部队,和大部队一起等待,被允许了(不然就还是在挂起状态),才能有下一次争锁的机会,争到了锁才能运行)
方法三:
使用特殊域变量volatile实现线程同步
方法四:
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。
ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
方法五:
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
方法六:
使用阻塞队列实现线程同步
方法七.
使用原子变量实现线程同步
面试题:线程池、核心线程数、最小线程数
线程间通信:不同任务的线程操作同一个对象,合作/协作/协同/同步?完成一个整个一个事儿的时候(官方:多个线程在处理同一个资源,但是处理的动作(线程的任务),却不相同)。(生产者消费者例子)。通过等待唤醒机制。
线程池(即一个线程的容器):因为线程创建和销毁需要时间,如果一件事需要大量并发线程且每个线程很短时间就完成任务了,为了避免大量运行时间耗费在创建和销毁(避免过多消耗资源),即为了实现线程的复用(不销毁,接着用(执行其他任务)),可以使用线程池技术。容器推荐用LinkedList(底层链表,线程安全)。
JAVA基础:ArrayList和LinkedList区别
https://www.cnblogs.com/showme1942/p/10059559.html
【目前有一个想法,把线程技术作为自己的招牌】
P334 lambda编程:函数式编程思想,只关注()→{}就完事了
浅谈ThreadLocal
https://zhuanlan.zhihu.com/p/60375306
ThreadLocal项目案例
https://zhuanlan.zhihu.com/p/60665911
线程安全练习-经典:生产者消费者
原文:生产者/消费者问题的多种Java实现方式
https://blog.csdn.net/monkey_d_meng/article/details/6251879
仓库:
import java.util.LinkedList;
/**
* 仓库类Storage实现缓冲区
*/
public class Storage
{
// 仓库最大存储量
private final int MAX_SIZE = 100;
// 仓库存储的载体
private LinkedList<Object> list = new LinkedList<Object>();
// 生产num个产品
public void produce(int num)
{
// 同步代码段/块
synchronized (list)
{
// 如果仓库剩余容量不足
while (list.size() + num > MAX_SIZE)
{
System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:"
+ list.size() + "/t暂时不能执行生产任务!");
try
{
// 由于条件不满足,生产阻塞
list.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 生产条件满足情况下,生产num个产品
for (int i = 1; i <= num; ++i)
{
list.add(new Object());
}
System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size());
list.notifyAll();
}
}
// 消费num个产品
public void consume(int num)
{
// 同步代码段
synchronized (list)
{
// 如果仓库存储量不足
while (list.size() < num)
{
System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:"
+ list.size() + "/t暂时不能执行生产任务!");
try
{
// 由于条件不满足,消费阻塞
list.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 消费条件满足情况下,消费num个产品
for (int i = 1; i <= num; ++i)
{
list.remove();
}
System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size());
list.notifyAll();
}
}
// get/set方法
public LinkedList<Object> getList()
{
return list;
}
public void setList(LinkedList<Object> list)
{
this.list = list;
}
public int getMAX_SIZE()
{
return MAX_SIZE;
}
}
生产者:
/**
* 生产者类Producer继承线程类Thread
*/
public class Producer extends Thread
{
// 每次生产的产品数量
private int num;
// 所在放置的仓库
private Storage storage;
// 构造函数,设置仓库 //这么写,到时候,符合开闭原则(如果Storage是个接口,你到时候是需要放实现类的话,你就能感受到了)
public Producer(Storage storage)
{
this.storage = storage;
}
// 线程run函数
public void run()
{
produce(num);
}
// 调用仓库Storage的生产函数
public void produce(int num)
{
storage.produce(num);
}
// get/set方法
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
public Storage getStorage()
{
return storage;
}
public void setStorage(Storage storage)
{
this.storage = storage;
}
}
消费者:
/**
* 消费者类Consumer继承线程类Thread
*/
public class Consumer extends Thread
{
// 每次消费的产品数量
private int num;
// 所在放置的仓库
private Storage storage;
// 构造函数,设置仓库
public Consumer(Storage storage)
{
this.storage = storage;
}
// 线程run函数
public void run()
{
consume(num);
}
// 调用仓库Storage的生产函数
public void consume(int num)
{
storage.consume(num);
}
// get/set方法
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
public Storage getStorage()
{
return storage;
}
public void setStorage(Storage storage)
{
this.storage = storage;
}
}
测试类:
/**
* 测试类Test
*/
public class Test
{
public static void main(String[] args)
{
// 仓库对象
Storage storage = new Storage();
// 生产者对象
Producer p1 = new Producer(storage);
Producer p2 = new Producer(storage);
Producer p3 = new Producer(storage);
Producer p4 = new Producer(storage);
Producer p5 = new Producer(storage);
Producer p6 = new Producer(storage);
Producer p7 = new Producer(storage);
// 消费者对象
Consumer c1 = new Consumer(storage);
Consumer c2 = new Consumer(storage);
Consumer c3 = new Consumer(storage);
// 设置生产者产品生产数量
p1.setNum(10);
p2.setNum(10);
p3.setNum(10);
p4.setNum(10);
p5.setNum(10);
p6.setNum(10);
p7.setNum(80);
// 设置消费者产品消费数量
c1.setNum(50);
c2.setNum(20);
c3.setNum(30);
// 线程开始执行
c1.start();
c2.start();
c3.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
}
---------------------------控制台打印提示语---------------------------------
运行结果,控制台打印:
【要消费的产品数量】:50 【库存量】:0 暂时不能执行生产任务!
【要消费的产品数量】:30 【库存量】:0 暂时不能执行生产任务!
【要消费的产品数量】:20 【库存量】:0 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:10
【要消费的产品数量】:20 【库存量】:10 暂时不能执行生产任务!
【要消费的产品数量】:30 【库存量】:10 暂时不能执行生产任务!
【要消费的产品数量】:50 【库存量】:10 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:20
【要消费的产品数量】:50 【库存量】:20 暂时不能执行生产任务!
【要消费的产品数量】:30 【库存量】:20 暂时不能执行生产任务!
【已经消费产品数】:20 【现仓储量为】:0
【已经生产产品数】:10 【现仓储量为】:10
【已经生产产品数】:10 【现仓储量为】:20
【已经生产产品数】:80 【现仓储量为】:100
【要生产的产品数量】:10 【库存量】:100 暂时不能执行生产任务!
【已经消费产品数】:30 【现仓储量为】:70
【已经消费产品数】:50 【现仓储量为】:20
【已经生产产品数】:10 【现仓储量为】:30
【已经生产产品数】:10 【现仓储量为】:40