一、认识线程
1.1线程如何启动
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this); // 加入一个线程组
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0(); // 调用本地C++代码 Java没有权限
Java无法直接操作硬件,要通过native调用本地方法,由底层的C++开启线程。
1.2并发和并行
并发(多个线程操作同一个资源)
- CPU一核 ,模拟出来多条线程,快速交替各个线程产生假象
并行(多个线程一起运行)
- CUP多核,同一个时间,多个线程同时执行。
public class Dome01 {
public static void main(String[] args) {
// 获取CPU的核数
// CPU 密集型,IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
并发编程的本质:充分利用CPU的资源
1.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>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.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; // 终止
}
wait/sleep 区别:
- 来自不同的类
- wait =》 Object
- sleep =》 Thread
- 关于锁的释放
- wait会释放锁
- sleep 不会释放锁
- 使用范围
- wait必须在同步代码块中使用
- sleep可以再任何地方使用
二、synchronized锁与Lock锁
2.1 synchronized
接下来我们来看一个售票的小栗子:
/**
* 售票
*/
public class SaleTicketDome01 {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}).start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}).start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}).start();
}
}
class Ticket {
private int number = 50;
// synchronized 锁
public synchronized void sale(){
if (number > 0){
System.out.println(Thread.currentThread().getName()
+"卖出了"+(number--)+"张票,剩余"+number);
}
}
}
这是一个售票的小程序,sale()售票方法被synchronized 修饰。防止出现两个人抢到同一张票的问题。
2.2 Lock锁
ReentrantLock()
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync(); // 如果是一个无参构造的话就是一个非公平锁
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
// 如果传入的是一个布尔类型
// true:公平锁
// false:非公平锁
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁:先来后到
非公平锁:可以插队(默认)
接下来我们看一看使用Lock锁的售票系统
/**
* 售票
* 公司中的开发
* 不会继承Thread 或 实现Runable接口
*/
public class SaleTicketDome01 {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(()->{ for (int i = 0; i < 40; i++) ticket.sale(); },"一号口").start();
new Thread(()->{ for (int i = 0; i < 40; i++) ticket.sale(); },"二号口").start();
new Thread(()->{ for (int i = 0; i < 40; i++) ticket.sale(); },"三号口").start();
}
}
/**
* Lock 三部曲
* new ReentrantLock();
* lock.lock(); 加锁
* lock.unlock(); 解锁
*/
class Ticket {
private int number = 50;
Lock lock = new ReentrantLock();
public void sale(){
lock.lock(); // 加锁
try {
if (number > 0){
System.out.println(Thread.currentThread().getName()
+"卖出了第: "+(number--)+"张票 ======> 剩余"+number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock(); // 解锁
}
}
}
Synchronized 和 Lock 区别:
- Synchronized 是内置的java关键字,Lock 是一个java类
- Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
- Synchronized 会自动释放锁,Lock 必须要手动解锁,如果不释放会死锁
- Synchronized 线程1(获得锁,阻塞),线程2(等待,一直等),Lock锁就不一定会等待
- Synchronized 可重入锁,不可以中断的,非公平,Lock 可重入锁,可以判断锁,可以设置公平非公平锁
- Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码
2.3 synchronized线程通讯
2.3.1 synchronized线程通讯方法
Thread.wait():使当前线程进入等待状态。
Thread notify():通知wait的线程唤醒。
2.3.2生产者消费者问题
public class ProducerConsumer {
public static void main(String[] args) {
Product product = new Product();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
product.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
product.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
/**
* 等待
* 业务
* 通知
*/
class Product{
private int number = 0;
// +1
public synchronized void increment() throws InterruptedException {
if (number != 0){ // 等待-1
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"===》"+number);
this.notify();
// 通知其他线程 number 已经增加
}
// -1
public synchronized void decrement() throws InterruptedException {
if (number == 0){ // 等待+1
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"===》"+number);
this.notify();
// 通知其他线程 number 已经减少
}
}
如果有A,B,C,D四个线程;此程序就不再安全;存在虚假唤醒情况
解决方法:if 循环换为 while循环
class Product{
private int number = 0;
// +1
public synchronized void increment() throws InterruptedException {
while(number != 0){ // 等待-1
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"===》"+number);
this.notify();
// 通知其他线程 number 已经增加
}
// -1
public synchronized void decrement() throws InterruptedException {
while(number == 0){ // 等待+1
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"===》"+number);
this.notify();
// 通知其他线程 number 已经减少
}
}
2.4Lock线程通讯
2.4.1 Lock线程通讯方法
newCondition() // 可以获得一个 Condition对象
Conditition作用就是替换Object类中wait notify 方法
Condition.await() // 让当前线程进入等待
Condition.signal() // 唤醒一个等待的线程
2.4.2 生产者消费者问题
public class ProducerConsumer {
public static void main(String[] args) {
Product product = new Product();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
product.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
product.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
product.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
product.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
/**
* 等待
* 业务
* 通知
*/
class Product{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// +1
public void increment() throws InterruptedException {
lock.lock();
try {
while (number != 0) { // 等待-1
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "===》" + number);
condition.signalAll();
// 通知其他线程 number 已经增加
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
// -1
public void decrement() throws InterruptedException {
lock.lock();
try {
while(number == 0){ // 等待+1
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"===》"+number);
// 通知其他线程 number 已经减少
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
2.4.3 Condition的优势
Condition可以精准的通知和唤醒线程,就以上程序来说,可以让 A、B 、C、D有序的执行
/**
* Condition 顺序执行
* A->B->C->A
*/
public class ConditionDominant {
public static void main(String[] args) {
Dome_01 dome = new Dome_01();
new Thread(()->{
for (int i = 0; i < 10; i++) {
dome.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
dome.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
dome.printC();
}
},"C").start();
}
}
class Dome_01{
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
private int number = 1;
public void printA(){
lock.lock();
try {
// 业务 判断 执行 通知
while (number != 1){
conditionA.await();
}
System.out.println(Thread.currentThread().getName()+"====>A在执行");
// 唤醒指定的人
// 唤醒conditionB
number = 2;
conditionB.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (number != 2){
conditionB.await();
}
System.out.println(Thread.currentThread().getName()+"====>B在执行");
number = 3;
conditionC.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (number != 3){
conditionC.await();
}
System.out.println(Thread.currentThread().getName()+"====>C在执行");
number = 1;
conditionA.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
感谢阅读
欢迎留言