什么是JUC
Java.util.Concurrent 包
进程和线程
- 区别:一个进程中可以有多个线程执行
- 线程状态
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区别
sleep是Thread的静态方法;wait是Object的方法任何对象实例都可以调用
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis 参数是睡眠的毫秒数
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*如果秒数是负的抛出异常
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
/**
* Causes the current thread to wait until another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object.
* In other words, this method behaves exactly as if it simply
* performs the call {@code wait(0)}.
* <p>
* The current thread must own this object's monitor. The thread
* releases ownership of this monitor and waits until another thread
* notifies threads waiting on this object's monitor to wake up
* either through a call to the {@code notify} method or the
* {@code notifyAll} method. The thread then waits until it can
* re-obtain ownership of the monitor and resumes execution.
* <p>
* As in the one argument version, interrupts and spurious wakeups are
* possible, and this method should always be used in a loop:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* ... // Perform action appropriate to condition
* }
* </pre>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws InterruptedException if any thread interrupted the
* current thread before or while the current thread
* was waiting for a notification. The <i>interrupted
* status</i> of the current thread is cleared when
* this exception is thrown.
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
*/
public final void wait() throws InterruptedException {
wait(0);
}
sleep不会释放锁,也不需要占用锁;wait会释放锁,当被notify时
都可以被interrupted方法中断
4. 管程,就是Monitor监视器,也被称为锁。是一种同步机制,保证同一时间,只有一个线程访问被保护的数据或者代码。JVM中同步进入和退出都是基于管程对象实现的
5. 用户线程和守护线程
用户线程:自定义线程
守护线程:比如垃圾回收
示例:主线程结束了,用户线程还在运行,jvm存活
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "----" + Thread.currentThread().isDaemon());
while(true){
}
},"aa");
thread.start();
System.out.println(Thread.currentThread().getName()+" over");
}
}
示例: 没有用户线程了,都是守护线程,jvm结束
package com.example.juclearn;
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "----" + Thread.currentThread().isDaemon());
while(true){
}
},"aa");
thread.setDaemon(true);
thread.start();
System.out.println(Thread.currentThread().getName()+" over");
}
}
========================= Lock接口 ==============================
Synchronized关键字
- 修饰一个代码块,被修饰的代码块称为同步语句块,作用范围是{}括起来的代码,作用对象是调用这个代码块的对象
- 修饰一个方法,被修饰的方法成为同步方法,作用范围是整个方法,作用对象是调用这个方法的对象。synchronized关键字不能被继承
- 修饰一个静态的方法,作用范围是整个静态方法,作用的对象是这个类的所有对象
- 修饰一个类,作用范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象
Synchronized实现卖票例子
package com.example.juclearn;
/**
* 多线程编程实现卖票例子 3个售货员卖30张票
*/
/**
* 第一步,创建资源类,在类中创建属性和操作方法
*/
class Ticket{
private int number = 30;
/**
* 售票方法
*/
public synchronized void sale(){
if (number > 0){
System.out.println(Thread.currentThread().getName() + "卖第"+ (30-number--+1) +"张票,还剩" + number + "张");
}
}
}
public class TestSynchronized {
public static void main(String[] args) {
Ticket ticket = new Ticket();
// 创建多个线程 调用资源类的方法
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++){
ticket.sale();
}
}
}, "AA").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++){
ticket.sale();
}
}
}, "BB").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++){
ticket.sale();
}
}
}, "CC").start();
}
}
Lock接口
- 实现了比使用synchronized方法和语句可获得的更广泛的锁定操作
- 实现类有ReentrantLock(可重入锁)、ReentrantreadWriteLock.ReadLock、ReentrantreadWriteLock.WriteLock
- Lock 和Synchronized区别
Lock不是Java语言内置的,是一个类;Synchronized是Java语言的关键字,是内置的
synchronized不需要用户手动释放锁;Lock必须手动释放锁,否则会出现死锁
Lock可以让等待锁的线程响应中断;Synchronized会让等待的线程一直等待下去
Lock可以得知有没有获得锁;Synchronized不能
Lock可以提高多个线程进行读操作的效率
package com.example.juclearn.lock;
/**
* 多线程编程实现卖票例子 3个售货员卖30张票
*/
import java.util.concurrent.locks.ReentrantLock;
/**
* 第一步,创建资源类,在类中创建属性和操作方法
*/
class Ticket{
private int number = 30;
private final ReentrantLock reentrantLock = new ReentrantLock();
/**
* 售票方法
*/
public void sale(){
reentrantLock.lock();
try {
if (number > 0){
System.out.println(Thread.currentThread().getName() + "卖第"+ (30-number--+1) +"张票,还剩" + number + "张");
}
}finally {
reentrantLock.unlock();
}
}
}
public class TestLock {
public static void main(String[] args) {
// 创建多个线程 调用资源类的方法
Ticket ticket = new Ticket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"AA").start();
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();
}
}
注:start方法最终调用的本地方法,何时调用由操作系统决定
========================= 线程间通信 ============================
多线程编程步骤:
1 创建资源类,创建属性和方法
2 在资源类中判断、干活、通知(新增)
3 创建多个线程,调用资源类的操作方法
Synchronized实现案例
实例:有两个线程其中一个线程实现对值 +1,另一个线程实现对值 -1
package com.example.juclearn.sync;
class Share {
private int number = 0;
public synchronized void incr() throws InterruptedException {
// 判断
if (number != 0){
this.wait();
}
// 干活
number++;
System.out.println(Thread.currentThread().getName() + "::" + number);
// 通知
this.notifyAll();
}
public synchronized void decr() throws InterruptedException {
// 判断
if (number != 1){
this.wait();
}
// 干活
number--;
System.out.println(Thread.currentThread().getName() + "::" + number);
// 通知
this.notifyAll();
}
}
public class ThreadComDemo1 {
public static void main(String[] args) {
Share share = new Share();
new Thread(()->{
for (int i = 0; i <