共计 13225 个字符,预计需要花费 34 分钟才能阅读完成。
创立和启动线程的形式一
- 自定义类 继承 Thread 类 并重写 run 办法,而后创立该类的对象调用 start 办法。
创立和启动线程的形式二
- 自定义类 实现 Runnable 接口 并重写 run 办法,创立该类的对象作为实参来结构 Thread 类型的对象,而后应用 Thread 类型的对象调用 start 办法。
public static void main(String[] args) {new Thread(){
@Override
public void run() {System.out.println("t1");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {System.out.println("t2");
}
}).start();
new Thread(()->{System.out.println("t3");
}).start();}
1. 继承形式治理线程编号和名称
public class ThreadIdNameTest extends Thread{public ThreadIdNameTest(String sun) {
// 调用父类的构造方法
super(sun);
}
@Override
public void run() {System.out.println("子线程的 ID:" + this.getId());
System.out.println("子线程的名称:" + getName());
}
public static void main(String[] args) {ThreadIdNameTest t1 = new ThreadIdNameTest("sun");
t1.start();
System.out.println("主线程的 ID:" + Thread.currentThread().getId());
System.out.println("主线程的名称:" + Thread.currentThread().getName());
}
}
===========
主线程的 ID:1
子线程的名称:sun
主线程的名称:main
2. 接口的形式治理线程编号和名称
public class MainTest {public static void main(String[] args) {new Thread(()->{System.out.println("子线程的 ID:" + Thread.currentThread().getId());
System.out.println("子线程的名称:" + Thread.currentThread().getName());
Thread.currentThread().setName("tttt");
System.out.println("子线程的名称:" + Thread.currentThread().getName());
}).start();
System.out.println("主线程的 ID:" + Thread.currentThread().getId());
System.out.println("主线程的名称:" + Thread.currentThread().getName());
}
}
===========
子线程的 ID:14
主线程的 ID:1
子线程的名称:Thread-0
主线程的名称:main
子线程的名称:tttt
3. 罕用的办法
-
Sleep
public class ThreadSleepTest extends Thread {
private boolean flag = true;
@Override
public void run() {while (flag) {LocalDateTime now = LocalDateTime.now();
String time = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm"));
System.out.println(time);
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}
}
}
public static void main(String[] args) {ThreadSleepTest t1 = new ThreadSleepTest();
t1.start();
try {Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
t1.flag = false;
}
}
-
守护线程
public class ThreadDaemonTest extends Thread{
@Override
public void run() {
// 默认不是守护线程
// 当子线程不是守护线程时,尽管主线程先完结了,然而子线程仍然会继续执行,直到打印所有数据为止
// 当子线程是守护时,当主线程完结后,则子线程随之完结
for(int i = 0;i < 50;i++){System.out.println("子线程:i ="+ i);
}
}
public static void main(String[] args) {ThreadDaemonTest t1 = new ThreadDaemonTest();
// 必须在线程启动之前设置子线程为守护线程
t1.setDaemon(true);
t1.start();
for(int i = 0;i < 20;i++){System.out.println("主线程:i ="+ i);
}
}
}
-
join 期待该线程终止
/**
* @Author 振帅
* @Date 2021/05/26 21:49
*/
public class ThreadJoinTest {public static void main(String[] args) {
// 偶数
Thread t1 = new Thread(()->{for(int i = 0;i < 100;i += 2){System.out.println("ti==:" + i);
}
});
// 奇数
Thread t2 = new Thread(()->{for(int i = 1;i < 100;i += 2){System.out.println("t2:" + i);
}
});
System.out.println("主线程开始");
t1.start();
t2.start();
try {t1.join();
t2.join();} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("主线程完结");
}
}
线程同步机制
1. 同步代码块实现线程同步形式一
- synchronized (dm)
/**
* @Author 振帅
* @Date 2021/05/26 22:39
* synchronized 模仿取钱
*/
public class AccountRunnableTest implements Runnable{class Demo {}
// 锁
Demo dm = new Demo();
// 账户余额
private int balance;
public AccountRunnableTest(int balance) {this.balance = balance;}
public int getBalance() {return balance;}
public void setBalance(int balance) {this.balance = balance;}
@Override
public void run() {System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
//synchronized (new Demo()){ // 锁不住
synchronized (dm){
//1. 模仿从后盾查问余额
int temp = getBalance();
//2. 模仿取款 200
if (temp > 200) {System.out.println("正在出钞,请稍后...");
temp -= 200;
try {Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
} else {System.out.println("余额有余");
}
//3. 更新余额
setBalance(temp);
}
}
public static void main(String[] args) {AccountRunnableTest account = new AccountRunnableTest(1000);
Thread t1 = new Thread(account);
Thread t2 = new Thread(account);
t1.start();
t2.start();
System.out.println("主线程开始期待...");
try {t1.join();
t2.join();} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("最终账户余额为:"+ account.getBalance());
}
}
2. 同步代码块实现线程同步形式二
- static 润饰锁
/**
* @Author 振帅
* @Date 2021/05/26 22:39
* synchronized 模仿取钱
*/
public class AccountThreadTest extends Thread{static class Demo {}
// 锁 属于类层级 所有对象共享一个
private static Demo dm = new Demo();
// 账户余额
private int balance;
public AccountThreadTest(int balance) {this.balance = balance;}
public int getBalance() {return balance;}
public void setBalance(int balance) {this.balance = balance;}
@Override
public void run() {System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
synchronized (dm){
//1. 模仿从后盾查问余额
int temp = getBalance();
//2. 模仿取款 200
if (temp > 200) {System.out.println("正在出钞,请稍后...");
temp -= 200;
try {Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
} else {System.out.println("余额有余");
}
//3. 更新余额
setBalance(temp);
}
}
public static void main(String[] args) {AccountThreadTest at1 = new AccountThreadTest(1000);
AccountThreadTest at2 = new AccountThreadTest(1000);
at1.start();
at2.start();
System.out.println("主线程开始期待...");
try {at1.join();
at2.join();} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("at1 账户余额为:"+ at1.getBalance());
System.out.println("at2 账户余额为:"+ at2.getBalance());
}
}
3. 同步办法块实现线程同步形式一
- 应用 synchronized 锁住整个办法
/**
* @Author 振帅
* @Date 2021/05/26 22:39
* synchronized 模仿取钱
*/
public class AccountRunnableTest implements Runnable{
// 账户余额
private int balance;
public AccountRunnableTest(int balance) {this.balance = balance;}
public int getBalance() {return balance;}
public void setBalance(int balance) {this.balance = balance;}
@Override
public synchronized void run() {System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
//1. 模仿从后盾查问余额
int temp = getBalance();
//2. 模仿取款 200
if (temp > 200) {System.out.println("正在出钞,请稍后...");
temp -= 200;
try {Thread.sleep(3000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
} else {System.out.println("余额有余");
}
//3. 更新余额
setBalance(temp);
}
public static void main(String[] args) {AccountRunnableTest account = new AccountRunnableTest(1000);
Thread t1 = new Thread(account);
Thread t2 = new Thread(account);
t1.start();
t2.start();
System.out.println("主线程开始期待...");
try {t1.join();
t2.join();} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("最终账户余额为:"+ account
.getBalance());
}
}
该形式等价于:
synchronized(this) {整个办法体的代码}
this 代表调用 run 办法的对象,由源码可知 调用 run 办法的对象是account
因而 synchronized(this){} 能够锁住
@Override
public void run() {synchronized (this){System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
//1. 模仿从后盾查问余额
int temp = getBalance();
//2. 模仿取款 200
if (temp > 200) {System.out.println("正在出钞,请稍后...");
temp -= 200;
try {Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
} else {System.out.println("余额有余");
}
//3. 更新余额
setBalance(temp);
}
}
4. 同步办法块实现线程同步形式二
- 当咱们对一个静态方法加锁,如:
public synchronized static void xxx(){….} - 那么该办法锁的对象是类对象。每个类都有惟一的一个类对象。获取类对象的形式: 类名.class。
- 静态方法与非静态方法同时应用了 synchronized 后它们之间是非互斥关系的。
- 起因在于:静态方法锁的是类对象而非静态方法锁的是以后办法所属对象。
/**
* @Author 振帅
* @Date 2021/05/26 22:39
* synchronized
*/
public class AccountThreadTest extends Thread{
// 账户余额
private int balance;
public AccountThreadTest(int balance) {this.balance = balance;}
public int getBalance() {return balance;}
public void setBalance(int balance) {this.balance = balance;}
public synchronized static void test(){System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
System.out.println("正在出钞,请稍后...");
try {Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
}
@Override
public void run() {test();
}
public static void main(String[] args) {AccountThreadTest at1 = new AccountThreadTest(1000);
AccountThreadTest at2 = new AccountThreadTest(1000);
at1.start();
at2.start();
System.out.println("主线程开始期待...");
try {at1.join();
at2.join();} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("at1 账户余额为:"+ at1.getBalance());
System.out.println("at2 账户余额为:"+ at2.getBalance());
}
}
等价于
public static void test(){synchronized(AccountThreadTest.class){System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
System.out.println("正在出钞,请稍后...");
try {Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
}
}
5. 应用 Lock(锁)实现线程同步
- 从 Java5 开始提供了更弱小的线程同步机制—应用显式定义的同步锁对象来实现。
- java.util.concurrent.locks.Lock 接口是管制多个线程对共享资源进行拜访的工具。
- 该接口的次要实现类是 ReentrantLock 类,该类领有与 synchronized 雷同的并发性,在当前的线程安全控制中,常常应用 ReentrantLock 类显式加锁和开释锁。
与 synchronized 形式的比拟
- Lock 是显式锁,须要手动实现开启和敞开操作,而 synchronized 是隐式锁,执行锁定代码后主动
开释。 - Lock 只有同步代码块形式的锁,而 synchronized 有同步代码块形式和同步办法两种锁。
- 应用 Lock 锁形式时,Java 虚拟机将破费较少的工夫来调度线程,因而性能更好。
/**
* @Author 振帅
* @Date 2021/05/26 22:39
* ReentrantLock 模仿取钱
*/
public class AccountRunnableTest implements Runnable{
// 账户余额
private int balance;
// 筹备锁
private ReentrantLock lock = new ReentrantLock();
public AccountRunnableTest(int balance) {this.balance = balance;}
public int getBalance() {return balance;}
public void setBalance(int balance) {this.balance = balance;}
@Override
public void run() {
// 开始加锁
lock.lock();
System.out.println("线程" + Thread.currentThread().getName() + "已启动...");
//1. 模仿从后盾查问余额
int temp = getBalance();
//2. 模仿取款 200
if (temp > 200) {System.out.println("正在出钞,请稍后...");
temp -= 200;
try {Thread.sleep(3000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("请取走你的钞票!");
} else {System.out.println("余额有余");
}
//3. 更新余额
setBalance(temp);
// 解锁
lock.unlock();}
public static void main(String[] args) {AccountRunnableTest account = new AccountRunnableTest(1000);
Thread t1 = new Thread(account);
Thread t2 = new Thread(account);
t1.start();
t2.start();
System.out.println("主线程开始期待...");
try {t1.join();
t2.join();} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("最终账户余额为:"+ account.getBalance());
}
}
线程通信
1.Object 类罕用的办法
办法申明 | 性能介绍 |
---|---|
void wait() | 用于使得线程进入期待状态,直到其它线程调用 notify()或 notifyAll()方 法 |
void wait(long timeout) | 用于进入期待状态,直到其它线程调用办法或参数指定的毫秒数曾经过来为止 |
void notify() | 用于唤醒期待的单个线程 |
void notifyAll() | 用于唤醒期待的所有线程 |
/**
* @Author 振帅
* @Date 2021/05/26 23:53
* 线程通信 两个线程交替打印 1 -100
*/
public class ThreadCommunicateTest implements Runnable {
private int cnt = 1;
@Override
public void run() {while (true) {synchronized (this){
// 用于唤醒期待的单个线程 写在锁外面
notify();
if(cnt <= 100){System.out.println("线程:"+ Thread.currentThread().getName() +"中的 cnt:=" +cnt);
try {Thread.sleep(200);
} catch (InterruptedException e) {e.printStackTrace();
}
cnt++;
try {// 用于使得线程进入期待状态,直到其它线程调用 notify()或 notifyAll()办法 写在锁外面
// 以后线程打印完一个数 为了避免持续打印 调用 wait()
wait();} catch (InterruptedException e) {e.printStackTrace();
}
}else {break;}
}
}
}
public static void main(String[] args) {ThreadCommunicateTest tc = new ThreadCommunicateTest();
Thread t1 = new Thread(tc);
Thread t2 = new Thread(tc);
t1.start();
t2.start();}
}
2. 生产者消费者模型实现
仓库类
/**
* @Author 振帅
* @Date 2021/05/27 0:20
* 仓库类
*/
public class StoreHouse {
// 记录产品的数量
private int cnt = 0;
// 生产办法
public synchronized void produceProduct(){notify();
if (cnt < 10) {System.out.println("线程"+Thread.currentThread().getName()+"正在生产第"+(cnt+1)+"个产品");
cnt++;
} else {
try {wait();
} catch (InterruptedException e) {e.printStackTrace();
}
}
}
// 生产办法
public synchronized void consumerProduct(){notify();
if (cnt > 0) {System.out.println("线程"+Thread.currentThread().getName()+"正在生产第"+(cnt)+"个产品");
cnt--;
} else {
try {wait();
} catch (InterruptedException e) {e.printStackTrace();
}
}
}
}
生产者
/**
* @Author 振帅
* @Date 2021/05/27 0:22
* 生产者
*/
public class ProduceThread extends Thread{
// 申明一个仓库类型的援用作为成员变量,为了能调用仓库类中的生产办法 合成复用准则
private StoreHouse storeHouse;
// 为了确保两个线程共用一个仓库
public ProduceThread(StoreHouse storeHouse){this.storeHouse = storeHouse;}
@Override
public void run() {while (true) {storeHouse.produceProduct();
try {Thread.sleep(500);
} catch (InterruptedException e) {e.printStackTrace();
}
}
}
}
消费者
/**
* @Author 振帅
* @Date 2021/05/27 0:22
* 消费者
*/
public class ConsumerThread extends Thread{
// 申明一个仓库类型的援用作为成员变量,为了能调用仓库类中的生产办法 合成复用准则
private StoreHouse storeHouse;
// 为了确保两个线程共用一个仓库
public ConsumerThread(StoreHouse storeHouse){this.storeHouse = storeHouse;}
@Override
public void run() {while (true) {storeHouse.consumerProduct();
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}
}
}
}
测试类
/**
* @Author 振帅
* @Date 2021/05/27 0:27
*/
public class StoreHouseTest {public static void main(String[] args) {
// 创立仓库类对象
StoreHouse storeHouse = new StoreHouse();
ProduceThread t1 = new ProduceThread(storeHouse);
ConsumerThread t2 = new ConsumerThread(storeHouse);
t1.start();
t2.start();}
}
创立和启动线程的形式三
- 实现 Callable 接口
- FutureTask 类 extends RunnableFuture extends Runnable
/**
* @Author 振帅
* @Date 2021/05/27 0:44
*/
public class ThreadCallableTest implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 计算 1 -10000 之间累加和
int sum = 0;
for (int i = 1;i <= 1000; i++){sum = sum+i;}
System.out.println("计算的后果为:" + sum);
return sum;
}
public static void main(String[] args) {ThreadCallableTest tct = new ThreadCallableTest();
// 用于形容可勾销的异步计算,该类提供了 Future 接口的根本实
// 现,包含启动和勾销计算、查问计算是否实现以及检索计算结果的办法,也能够用于获取办法调用
// 后的返回后果
FutureTask<Integer> task = new FutureTask<Integer>(tct);
Thread th = new Thread(task);
th.start();
Integer result = null;
try {
// 获取 call 办法计算的后果
result = task.get();} catch (InterruptedException e) {e.printStackTrace();
} catch (ExecutionException e) {e.printStackTrace();
}
System.out.println("线程处理结果:" + result);
}
}
创立和启动线程的形式四
- Executors 类
工具类和线程池的工厂类,能够创立并返回不同类型的线程池,罕用办法如下:
办法申明 | 性能介绍 |
---|---|
static ExecutorService newCachedThreadPool() | 创立一个可依据须要创立新线程的线程池 |
static ExecutorService newFixedThreadPool(int nThreads) | 创立一个可重用固定线程数的线程池 |
static ExecutorService newSingleThreadExecutor() | 创立一个只有一个线程的线程池 |
- ExecutorService 接口
真正的线程池接口,次要实现类是 ThreadPoolExecutor,罕用办法如下:
办法申明 | 性能介绍 |
---|---|
void execute(Runnable command) | 执行工作和命令,通常用于执行 Runnable |
Future submit(Callable task) | 执行工作和命令,通常用于执行 Callable |
void shutdown() | 启动有序敞开 |
public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(10);
ThreadCallableTest threadCallableTest = new ThreadCallableTest();
Future<Integer> future = executorService.submit(threadCallableTest);
Integer result = null;
try {result = future.get();
} catch (InterruptedException e) {e.printStackTrace();
} catch (ExecutionException e) {e.printStackTrace();
}
System.out.println("线程处理结果:" + result);
executorService.shutdown();}
}
正文完