写在前面
这里主要介绍一下如何使用Java多线程以及实现线程互斥。
一、线程的两种实现方式
- 继承
Thread
基类
public class Thread_Test extends Thread{
@Override
public void run() {
System.out.println("Thread is running.");
}
public static void main(String[] args) {
Thread_Test t = new Thread_Test();
// 启动线程,调用run方法
t.start();
}
}
- 实现
Runnable
接口(推荐使用)
public class Thread_Test implements Runnable{
@Override
public void run() {
System.out.println("Thread is running.");
}
public static void main(String[] args) {
Thread_Test t = new Thread_Test();
// 启动线程,调用run方法
Thread thread = new Thread(t);
thread.start();
}
}
二、线程池
- 使用线程池之后可以控制最大能够创建的线程,避免资源浪费;
- 如果要使用线程池的话,线程类只能是通过实现
Running
接口来实现; - 如果线程池耗尽,则后续的线程任务会等待有空闲的线程才会创建执行。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Thread_Test implements Runnable {
@Override
public void run() {
System.out.println("Thread is running.");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
// 最大线程数量
int threadNum = 2;
// 建立线程池
ExecutorService threadPool = Executors.newFixedThreadPool(threadNum);
while(true) {
Thread_Test t = new Thread_Test();
// 提交到线程池执行
threadPool.execute(t);
}
}
}
三、线程互斥
- 主要是使用了
synchronized
保留字; - 注意互斥锁的使用会相当影响运行效率,仅在必要时候使用;
- 一般有三种用法:
- 使用一个额外的类对象作为互斥锁
- 适用于需要进行多对象之间的线程互斥的情况;
- 额外的对象可以是最简单的类,无需具体实现,如下面的
Semaphore
类; - 这种用法最为普适。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Semaphore {}
public class Thread_Test implements Runnable {
private Semaphore semaphore;
public Thread_Test(Semaphore s) {
this.semaphore = s;
}
@Override
public void run() {
System.out.println("Thread is running.");
// 进入临界代码区
synchronized (semaphore) {
System.out.println("Enter critical code area.");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
// 最大线程数量
int threadNum = 2;
// 建立线程池
ExecutorService threadPool = Executors.newFixedThreadPool(threadNum);
// 互斥锁
Semaphore s = new Semaphore();
while(true) {
Thread_Test t = new Thread_Test(s);
// 提交到线程池执行
threadPool.execute(t);
}
}
}
- 使用本对象作为互斥锁
- 适用于同一个对象多次创建线程的情况;
- 只要是在同一个类中的函数需要互斥都可以使用;
- 使用
this
作为互斥锁。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Thread_Test implements Runnable {
public Thread_Test() {
// 进入临界代码区
synchronized (this) {
System.out.println("Main: Enter critical code area.");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void run() {
System.out.println("Thread is running.");
// 进入临界代码区
synchronized (this) {
System.out.println("Thread: Enter critical code area.");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
// 最大线程数量
int threadNum = 10;
// 建立线程池
ExecutorService threadPool = Executors.newFixedThreadPool(threadNum);
Thread_Test t = new Thread_Test();
while(true) {
// 提交到线程池执行
threadPool.execute(t);
}
}
}
- 直接使用
synchronized
修饰类内函数
- 本质上也是使用了
this
作为互斥锁; - 修饰的函数中的所有代码均为临界代码区。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Thread_Test implements Runnable {
public Thread_Test() {
}
public synchronized void read() {
System.out.println("Thread is reading.");
try {
Thread.currentThread().sleep(200);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void write() {
System.out.println("Thread is writing.");
try {
Thread.currentThread().sleep(200);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
System.out.println("Thread is running.");
this.read();
this.write();
}
public static void main(String[] args) {
// 最大线程数量
int threadNum = 5;
// 建立线程池
ExecutorService threadPool = Executors.newFixedThreadPool(threadNum);
Thread_Test t = new Thread_Test();
while(true) {
// 提交到线程池执行
threadPool.execute(t);
}
}
}