Java三大线程同步机制代码实战指南
作者:程序员码小跳
文章介绍了Java线程的五种状态(新建、就绪、运行、阻塞、死亡),以及线程的创建方式(继承Thread类、实现Runnable接口、实现Callable接口),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
线程状态

- 新建(New):当程序使用 new 关键字、Thread 类或其子类建立一个线程对象后,该线程就处于新建状态。它保持这个状态直到程序 start() 这个线程。(new MyThread)
- 就绪(Runnable 或Ready to Run):当线程对象调用了start()方法之后,该线程处于就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。(new MyThread.start() )
- 运行(Running):如果处于就绪状态的线程获得了 CPU,开始执行 run()方法的线程执行体,则该线程处于运行状态。
- 阻塞 (Blocked):如果一个线程执行了sleep、suspend等方法,失去CPU所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。
- 死亡(Dead):线程会以下面三种方式结束,结束后就是死亡状态。
- 正常结束:run()或 call()方法执行完成,线程正常结束。
- 异常结束:线程抛出一个未捕获的 Exception 或 Error。
- 调用结束:直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用
创建线程
继承Thread类[无入参、无返回值]
实现步骤:
1.创建一个Thread类的子类 class MyThread extends Thread 2.在Thread类的子类中重写Thread类中的run()方法 3.创建Thread类的子类对象 MyThread t1 = new MyThread(); 4.调用Thread类中的方法start()方法,开启新的线程,执行run方法 t1.start()
class MyThread extends Thread {
@Override
public void run() {
}
}
public class demo21Thread01 {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
}实现Runnable接口[无入参,无返回值]
实现步骤:
1.创建一个Runnable接口的实现类 class myThread implements Runnable
2.在实现类中重写Runnable接口的run方法
3.创建一个Runnable接口的实现类对象 myThread t1 = new myThread();
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象Thread t=new Thread(t1);
5.调用Thread类中的start方法,开启新的线程执行run方法 t.start()
class myThread02 implements Runnable {
public void run() {
}
}
public class demo21Thread01 {
public static void main(String args[]) throws InterruptedException {
myThread02 mythread = new myThread02();
Thread t = new Thread(mythread);
t.start();
}
}实现Callable接口[无入参,有返回值]
class MyTask implements Callable<String> {
@Override
public String call() throws Exception {
try {
// 模拟业务处理
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "success";
}
}
public class demo21Thread01 {
public static void main(String[] args) throws Exception {
// 1、callable怎么用,引入FutureTask初始化
FutureTask<String> futureTask = new FutureTask<>(new MyTask());
new Thread(futureTask).start();
// 2、FutureTask线程启动,与main线程互不干扰
while (!futureTask.isDone()) {
}
// 3、获得返回值:get方法尽量放在后面,一旦调用,线程等待等到执行完毕,会导致堵塞
String value = futureTask.get();
System.out.println("MyData的返回值:" + value);
}
}通过线程池方式
ExecutorService es= Executors.newCachedThreadPool(); //缓存型线程池 ExecutorService es= Executors.newFixedThreadPool(2); //固定型线程池 ExecutorService es=Executors.newSingleThreadExecutor(); //单线程型线程池 以上三种通过es.submit(new MyRunable03(i));提交任务 ScheduledExecutorService es = Executors.newScheduledThreadPool(3);//延迟执行或重复执行型线程池 通过es.schedule(new myRunnable(i), 2, TimeUnit.SECONDS);提交任务
通过lambda表达式
new Thread(() -> {
System.out.println("程序已启动");
}).start();
线程同步
3种让线程等待和唤醒的方法
方式1: Object中的wait()线程等待、notify()唤醒线程【PS:必须配合synchronized】
方式2: Condition的await()线程等待、signal()唤醒线程【PS:必须配合ReentrantLock】
方式3: LockSupport的park()线程等待、unpark()唤醒线程
package thread;
/*
* 两个线依次次输出1 2 3 4
*/
public class ThreadSyncTest2 {
// 使用专用锁对象(不可变)
private static Object LOCK = new Object();
private static int num = 1;
public static void main(String[] args) {
new Thread(() -> {
while (num <= 10) {
try {
synchronized (LOCK) {
if (num % 2 == 0) {
System.out.println("偶数线程A: " + num++);
LOCK.notify();
} else {
LOCK.wait();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "偶数线程A").start();
new Thread(() -> {
while (num <= 10) {
try {
synchronized (LOCK) {
if (num % 2 == 1) {
System.out.println("基数线程B: " + num++);
LOCK.notify();
} else {
LOCK.wait();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "基数线程B").start();
}
}package thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/*
* 两个线程一次输出1 2 3 4
*/
public class ThreadSyncTest3 {
private static int num = 1;
// 锁与条件变量
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Condition ODD_COND = LOCK.newCondition(); // 奇数条件队列
private static final Condition EVEN_COND = LOCK.newCondition(); // 偶数条件队列
public static void main(String[] args) {
new Thread(() -> {
while (num <= 10) {
LOCK.lock();
try {
if (num % 2 == 0) {
System.out.println("偶数线程A: " + num++);
ODD_COND.signal();
} else {
EVEN_COND.await();
}
} catch (InterruptedException e) {
break;
} finally {
LOCK.unlock();
}
}
EVEN_COND.signal();
}, "偶数线程A").start();
new Thread(() -> {
while (num <= 10) {
LOCK.lock();
try {
if (num % 2 == 1) {
System.out.println("基数线程B: " + num++);
EVEN_COND.signal();
} else {
ODD_COND.await();
}
} catch (InterruptedException e) {
break;
} finally {
LOCK.unlock();
}
}
EVEN_COND.signal();
}, "基数线程B").start();
}
}方式1和方式2存在的问题
1、线程先要获得并持有锁,必须在锁块(synchronized或lock)中,必须配合使用
2、必须要先等待后唤醒,线程才能够被唤醒
LockSupport主要是解决上面2个问题,LockSupport 类使用了一种名为 permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit 只有两个值 1 和零,默认是零,不能累积

到此这篇关于Java三大线程同步机制代码实战指南的文章就介绍到这了,更多相关java线程同步机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
