33-Java多线程-qianfeng-笔记
一、什么是多线程
①:什么是进程
②:什么是线程
③:进程与线程的区别
二、线程的组成
①:组成
②:线程的特点
③:创建线程的三种方式
01.【继承Thread类,重写run方法】
1. 代码实现
package com.example.d6_thread;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("子线程..........." + i);
}
}
}
package com.example.d6_thread;
public class TestThread {
public static void main(String[] args) {
// 1.创建线程对象
MyThread myThread = new MyThread();
// 2.启动线程
myThread.start();
// 3.主线程执行
for (int i = 0; i < 100; i++) {
System.out.println("主线程=======================" + i);
}
}
}
2.获取线程名称和Id
方式一:
方式二:
3.修改线程的名称
方式一:
方式二:
4. 窗口买票案例
package com.example.d6_thread;
public class TicketWin extends Thread{
private int ticketCount = 100;
public TicketWin() {
}
public TicketWin(String name) {
super(name);
}
@Override
public void run() {
while (ticketCount > 0){
System.out.println(Thread.currentThread().getName()+" 卖出了第 " + (101-ticketCount) + "张票~~~~");
ticketCount--;
}
}
}
package com.example.d6_thread;
public class TestTicket {
public static void main(String[] args) {
TicketWin ticketWin = new TicketWin("窗口1");
TicketWin ticketWin2 = new TicketWin("窗口2");
TicketWin ticketWin3 = new TicketWin("窗口3");
TicketWin ticketWin4 = new TicketWin("窗口4");
ticketWin.start();
ticketWin2.start();
ticketWin3.start();
ticketWin4.start();
}
}
02.【实现Runnable接口】
1.代码实现
方式一:
package com.example.d6_thread;
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程名称:" + Thread.currentThread().getName() + i);
}
}
}
package com.example.d6_thread;
public class TestRunnable {
public static void main(String[] args){
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable,"我的线程");
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("main...................." + i);
}
}
}
方式二:使用匿名内部类实现
package com.example.d6_thread;
public class TestRunnable {
public static void main(String[] args){
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程名称:" + Thread.currentThread().getName() + i);
}
}
};
// 创建线程对象
Thread thread = new Thread(runnable,"我的线程1 ");
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("main...................." + i);
}
}
}
2.Runnable案例1
package com.example.d7_runnableDemo;
public class Ticket implements Runnable{
private static int ticketNum = 100;
@Override
public void run() {
while (ticketNum > 0){
System.out.println("线程名称:" + Thread.currentThread().getName() + (101 - ticketNum));
ticketNum --;
}
}
}
package com.example.d7_runnableDemo;
public class TestTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread thread = new Thread(ticket,"窗口1 ");
Thread thread2 = new Thread(ticket,"窗口2 ");
Thread thread3 = new Thread(ticket,"窗口3 ");
Thread thread4 = new Thread(ticket,"窗口4 ");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
票数卖重的情况后面会解决
3.Runnable案例2
> 方式一:
package com.example.d7_runnableDemo;
public class BankCard {
private int money;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
package com.example.d7_runnableDemo;
public class AddMoney implements Runnable{
private BankCard bankCard;
public AddMoney(BankCard bankCard) {
this.bankCard = bankCard;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
bankCard.setMoney(bankCard.getMoney() + 1000);
System.out.println(Thread.currentThread().getName() + "存了1000元"+ " 余额为:" +bankCard.getMoney()+"元~");
}
}
}
package com.example.d7_runnableDemo;
public class SubMoney implements Runnable{
private BankCard bankCard;
public SubMoney(BankCard bankCard) {
this.bankCard = bankCard;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (bankCard.getMoney() >= 1000){
bankCard.setMoney(bankCard.getMoney() - 1000);
System.out.println(Thread.currentThread().getName() + "取了1000元"+ " 余额为:" +bankCard.getMoney()+"元!");
}else {
System.out.println("余额不足,赶快存钱。。。。。");
i--;
}
}
}
}
package com.example.d7_runnableDemo;
public class TestBankCard {
public static void main(String[] args) {
BankCard bankCard = new BankCard();
AddMoney addMoney = new AddMoney(bankCard);
SubMoney subMoney = new SubMoney(bankCard);
Thread thread = new Thread(addMoney,"小黑 ");
Thread thread1 = new Thread(subMoney, "小美 ");
thread.start();
thread1.start();
}
}
方式二:匿名内部类实现方式
package com.example.d7_runnableDemo;
public class TestBankCard2 {
public static void main(String[] args) {
BankCard bankCard = new BankCard();
Runnable add = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
bankCard.setMoney(bankCard.getMoney() + 1000);
System.out.println(Thread.currentThread().getName() + "存了1000元"+ " 余额为:" +bankCard.getMoney()+"元~");
}
}
};
Runnable sub = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (bankCard.getMoney() >= 1000){
bankCard.setMoney(bankCard.getMoney() - 1000);
System.out.println(Thread.currentThread().getName() + "取了1000元"+ " 余额为:" +bankCard.getMoney()+"元!");
}else {
System.out.println("余额不足,赶快存钱。。。。。");
i--;
}
}
}
};
new Thread(add,"小白 ").start();
new Thread(sub,"小美 ").start();
}
}
03.实现Callable
接口
计算1-100的和
1.用法一
在这里插入代码片package com.example.d10_executor;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThread {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建一个Callable对象 完成1-100的和
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "开始计算~");
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
};
// 将Callable 转换成可执行对象
FutureTask<Integer> futureTask = new FutureTask<>(callable);
// 创建线程并启动
new Thread(futureTask).start();
// 获取结果(等待Callable执行完毕)
Integer integer = futureTask.get();
System.out.println("结果是:" + integer);
}
}
2.用法二 (结合线程池使用)
package com.example.d10_executor;
import java.util.concurrent.*;
public class CallableThread2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(1);
// 2.提交任务
Future<Integer> future = pool.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum = 0;
System.out.println(Thread.currentThread().getName() + "开始计算~");
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
});
// 3.获取结果
Integer integer = future.get();
System.out.println("结果是:" + integer);
// 4.关闭线程池
pool.shutdown();
}
}
3.并发计算
package com.example.d10_executor;
import java.util.concurrent.*;
public class CallableThread3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1.创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
// 2.1 创建任务1
Future<Integer> future1 = pool.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum1 = 0;
System.out.println(Thread.currentThread().getName() + "计算开始~");
for (int i = 0; i < 50; i++) {
sum1 += i;
}
return sum1;
}
});
// 2.2 创建任务2
Future<Integer> future2 = pool.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum2 = 0;
System.out.println(Thread.currentThread().getName() + "计算开始~");
for (int i = 50; i < 100; i++) {
sum2 += i;
}
return sum2;
}
});
// 3.获取结果
Integer integer1 = future1.get();
Integer integer2 = future2.get();
System.out.println("结果是:" + (integer1 + integer2));
// 4.关闭线程池
pool.shutdown();
}
}
三、线程的状态
①:休眠 (sleep)
package com.example.d8_threadStatus;
public class SleepThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程名称: " + Thread.currentThread().getName() + ".........." + i);
try {
Thread.sleep(1000); // sleep异常不也能直接抛出
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package com.example.d8_threadStatus;
public class TestSleep {
public static void main(String[] args) {
SleepThread s1 = new SleepThread();
new Thread(s1).start();
SleepThread s2 = new SleepThread();
new Thread(s1).start();
}
}
②:放弃 (yield)
package com.example.d8_threadStatus;
public class YieldThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程名称:" + Thread.currentThread().getName() + ".........." + i);
Thread.yield();
}
}
}
package com.example.d8_threadStatus;
public class TestYield {
public static void main(String[] args) {
new Thread(new YieldThread()).start();
new Thread(new YieldThread()).start();
}
}
③:加入(join)
package com.example.d8_threadStatus;
public class JoinThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("线程名称: " + Thread.currentThread().getName() + ".........." + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package com.example.d8_threadStatus;
public class TestJoin {
public static void main(String[] args) {
JoinThread joinThread = new JoinThread();
joinThread.start();
for (int i = 0; i < 50; i++) {
System.out.println("main........." + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
使用Join 加入线程的情况如下
④:修改线程优先级(priority)
package com.example.d8_threadStatus;
public class PriorityThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "=================="+i);
}
}
}
package com.example.d8_threadStatus;
public class TestPriority {
public static void main(String[] args) {
// 创建线程
PriorityThread p1 = new PriorityThread();
p1.setName("p1");
PriorityThread p3 = new PriorityThread();
p3.setName("p3");
// 设置优先级
p1.setPriority(1);
p3.setPriority(10);
// 启动
p1.start();
p3.start();
}
}
⑤:守护线程(Daemon)
package com.example.d8_threadStatus;
public class DeamonThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "=========" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package com.example.d8_threadStatus;
public class TestDeamon {
public static void main(String[] args) {
DeamonThread d1 = new DeamonThread();
d1.setName("d1");
d1.setDaemon(true);
d1.start();
for (int i = 0; i < 10; i++) {
System.out.println("main............" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
⑥:线程状态(等待)
四、线程安全
①:线程安全问题
package com.example.d8_threadStatus;
import java.util.Arrays;
public class Test {
private static int index = 0;
public static void main(String[] args) throws InterruptedException {
String[] s = new String[5];
Runnable r1 = new Runnable() {
@Override
public void run() {
s[index] = "hello";
index++;
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
s[index] = "word";
index++;
}
};
Thread a = new Thread(r1, "r1");
Thread b = new Thread(r2, "r2");
a.start();
b.start();
// 加入线程保证a b 两个线程执行完
a.join();
b.join();
System.out.println(Arrays.toString(s));
}
}
②:同步代码块
01.方式一:
1.解决买票问题
package com.example.d7_runnableDemo;
public class Ticket implements Runnable{
private static int ticketNum = 100;
// 创建锁
private Object object = new Object();
@Override
public void run() {
while (true) {
synchronized (object){
if (ticketNum <= 0){
break;
}
System.out.println("线程名称:" + Thread.currentThread().getName() + (101 - ticketNum));
ticketNum --;
}
}
}
}
package com.example.d7_runnableDemo;
public class TestTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread thread = new Thread(ticket,"窗口1 ");
Thread thread2 = new Thread(ticket,"窗口2 ");
Thread thread3 = new Thread(ticket,"窗口3 ");
Thread thread4 = new Thread(ticket,"窗口4 ");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
2.解决存取钱问题
package com.example.d7_runnableDemo;
public class TestBankCard2 {
public static void main(String[] args) {
BankCard bankCard = new BankCard();
// 存钱
Runnable add = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (bankCard){
bankCard.setMoney(bankCard.getMoney() + 1000);
System.out.println(Thread.currentThread().getName() + "存了1000元"+ " 余额为:" +bankCard.getMoney()+"元~");
}
}
}
};
// 取钱
Runnable sub = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (bankCard){
if (bankCard.getMoney() >= 1000){
bankCard.setMoney(bankCard.getMoney() - 1000);
System.out.println(Thread.currentThread().getName() + "取了1000元"+ " 余额为:" +bankCard.getMoney()+"元!");
}else {
System.out.println("余额不足,赶快存钱。。。。。");
i--;
}
}
}
}
};
new Thread(add,"小白 ").start();
new Thread(sub,"小美 ").start();
}
}
02. 方式二:(同步方法)
package com.example.d7_runnableDemo;
public class Ticket implements Runnable{
private static int ticketNum = 100;
// 创建锁
private Object object = new Object();
@Override
public void run() {
while (true) {
if (!tick()){
break;
}
}
}
public synchronized boolean tick(){
if (ticketNum <= 0){
return false;
}
System.out.println("线程名称:" + Thread.currentThread().getName() + (101 - ticketNum));
ticketNum --;
return true;
}
}
③:同步规则
④:死锁
package com.example.d9_lock;
public class MyLock {
public static Object a = new Object();
public static Object b = new Object();
}
package com.example.d9_lock;
public class TestLock {
public static void main(String[] args) {
Boy boy = new Boy();
Girl girl = new Girl();
boy.start();
girl.start();
}
}
package com.example.d9_lock;
public class Boy extends Thread{
@Override
public void run() {
synchronized (MyLock.a){
System.out.println("男孩拿到了a");
synchronized (MyLock.b){
System.out.println("男孩拿到了b");
System.out.println("可以开始吃了");
}
}
}
}
package com.example.d9_lock;
public class Girl extends Thread{
@Override
public void run() {
synchronized (MyLock.b){
System.out.println("女孩拿到了b");
synchronized (MyLock.a){
System.out.println("女孩拿到了a");
System.out.println("可以开始吃了");
}
}
}
}
⑤:线程通信
package com.example.d9_lock;
public class AddAndSubMoney {
public static boolean flag = false;
public static BankCard bankCard = new BankCard();
private static AddAndSubMoney addAndSubMoney = new AddAndSubMoney();
// 存钱
public synchronized void sub1(){
while (!flag){ // false 没有钱
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
bankCard.setMoney(bankCard.getMoney() - 1000);
System.out.println(Thread.currentThread().getName() + "取了1000元,余额是"+bankCard.getMoney());
// 修改标记
flag = false;
// 唤醒存钱线程
this.notifyAll();
}
// 取钱
public synchronized void save(){
while (flag){ // true 有钱
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
bankCard.setMoney(bankCard.getMoney() + 1000);
System.out.println(Thread.currentThread().getName() + "存了1000元,余额是"+bankCard.getMoney());
// 修改标记
flag = true;
// 唤醒取钱线程
this.notifyAll();
}
public static void main(String[] args) {
Runnable add = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
addAndSubMoney.save();
}
}
};
Runnable sub = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
addAndSubMoney.sub1();
}
}
};
new Thread(sub,"小白").start();
new Thread(add,"小黑").start();
new Thread(sub,"小华").start();
new Thread(add,"小明").start();
}
}
经典问题(生产者 消费者)
package com.example.d9_lock;
public class ProductionAndConsumeBread {
private static ProductionAndConsumeBread p = new ProductionAndConsumeBread();
// 存放面包的数组
private static Bread[] breads = new Bread[6];
// 存放面包的位置
private static int index = 0;
// 存放面包
public synchronized void intBread(Bread bread){
// 判断容器有没有满
if (index >= breads.length){
// 满了,加入队列
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
breads[index] = bread;
System.out.println(Thread.currentThread().getName() + "存了一个面包,剩余面包 "+(index + 1) + " 个");
index ++;
this.notifyAll();
}
// 取出面包
public synchronized void outBread(){
// 判断容器是否还有面包
if (index <= 0){
// 没有面包
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
breads[index - 1] = null;
System.out.println(Thread.currentThread().getName() + "取了一个面包,剩余面包 "+(index -1) + " 个");
index --;
this.notifyAll();
}
public static void main(String[] args) {
Runnable add = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
p.intBread(new Bread(i,Thread.currentThread().getName()));
}
}
};
Runnable out = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
p.outBread();
}
}
};
new Thread(add,"小虎").start();
new Thread(out,"小白").start();
}
}
⑥:小结
五、线程池
①:线程池概念
原理
②:创建线程池
package com.example.d10_executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CreateExecutor {
public static void main(String[] args) {
// 1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
// 2.创建任务
final int[] index = {0};
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true){
if (index[0] >= 100){
break;
}
System.out.println(Thread.currentThread().getName() + "卖了第" + (index[0] + 1) + "张票");
index[0]++;
}
}
};
// 3.将任务提交给线程池
for (int i = 0; i < 4; i++) {
pool.submit(runnable);
}
// 4. 关闭线程池
pool.shutdown(); // 等待任务所有执行完毕然后关闭线程池
// pool.shutdownNow(); // 不等待任务执行完毕就会关闭线程池
}
}
③:Future接口
## ④:异步和同步
同步:
异步:
六、Lock接口
①:重入锁
package com.example.d9_lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ReentrantLock2 {
private Lock lock = new ReentrantLock();
private String[] strs = {"A","B","","",""};
private int count = 2;
public void add(String str){
lock.lock(); // 开启锁
try {
strs[count] = str;
count++;
System.out.println(Thread.currentThread().getName() + "添加了元素" + str);
}finally {
lock.unlock(); // 释放锁
}
}
public String[] getStrs() {
return strs;
}
}
package com.example.d9_lock;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyLock2 {
private static ReentrantLock2 rl = new ReentrantLock2();
public static void main(String[] args) {
// 创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new Runnable() {
@Override
public void run() {
rl.add("Word");
}
});
pool.submit(new Runnable() {
@Override
public void run() {
rl.add("Hello");
}
});
pool.shutdown();
String[] strs = rl.getStrs();
System.out.println(Arrays.toString(strs));
}
}
②:使用Lock完成窗口买票
方法一:
package com.example.d9_lock;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TicketLock {
private static MyLock3 myLock3 = new MyLock3();
public static void main(String[] args) {
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(4);
// 提交任务
for (int i = 0; i < 4; i++) {
pool.submit(myLock3);
}
// 关闭线程池
pool.shutdown();
}
}
class MyLock3 implements Runnable {
private static Lock lock = new ReentrantLock();
private static int number = 0;
@Override
public void run() {
while (true) {
lock.lock(); // 开启锁
try {
if (number >= 1000){
break;
}
System.out.println(Thread.currentThread().getName() + "卖了第" + (number + 1) + "张票");
number++;
} finally {
lock.unlock(); //释放锁
}
}
}
}
方法二:
package com.example.d9_lock;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TicketLock2 {
private static TicketLock2 ticketLock2 = new TicketLock2();
private static Lock lock = new ReentrantLock();
private static int number = 0;
public void ticket(){
while (true) {
lock.lock(); // 开启锁
try {
if (number >= 1000){
break;
}
System.out.println(Thread.currentThread().getName() + "卖了第" + (number + 1) + "张票");
number++;
} finally {
lock.unlock(); //释放锁
}
}
}
public static void main(String[] args) {
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(4);
// 提交任务
for (int i = 0; i < 4; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
ticketLock2.ticket();
}
});
}
// 关闭线程池
pool.shutdown();
}
}
③:读写锁
01.使用读写锁
package com.example.readAndWirteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
public class ReadWriteDemo {
// 创建读写锁
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
// 获取读锁
private ReadLock readLock = rwl.readLock();
// 获取写锁
private WriteLock writeLock = rwl.writeLock();
private String value;
// 读锁
public String getValue(){
readLock.lock();
try {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("读取:" + value);
return this.value;
}finally {
readLock.unlock();
}
}
// 写锁
public void setValue(String value){
writeLock.lock();
try{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("写入:" + value);
this.value = value;
}finally {
writeLock.unlock();
}
}
}
package com.example.readAndWirteLock;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ReadWriteTest {
private static Random random = new Random();
public static void main(String[] args) {
Long start = System.currentTimeMillis();
ReadWriteDemo readWriteDemo = new ReadWriteDemo();
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(200);
// 分配20个写操作
for (int i = 0; i < 20; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
readWriteDemo.setValue("小黑: " + random.nextInt(1000));
}
});
}
// 分配180个读操作
for (int i = 0; i < 180; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
readWriteDemo.getValue();
}
});
}
// 关闭线程池
pool.shutdown();
while (!pool.isTerminated()){
}
Long end = System.currentTimeMillis();
System.out.println("使用读写锁用时:" + (end - start));
}
}
02.不使用读写锁
package com.example.readAndWirteLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReadWriteDemo {
private static Lock lock = new ReentrantLock();
private String value;
// 读锁
public String getValue(){
lock.lock();
try {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("读取:" + value);
return this.value;
}finally {
lock.unlock();
}
}
// 写锁
public void setValue(String value){
lock.lock();
try{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("写入:" + value);
this.value = value;
}finally {
lock.unlock();
}
}
}
package com.example.readAndWirteLock;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ReadWriteTest {
private static Random random = new Random();
public static void main(String[] args) {
Long start = System.currentTimeMillis();
ReadWriteDemo readWriteDemo = new ReadWriteDemo();
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(200);
// 分配20个写操作
for (int i = 0; i < 20; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
readWriteDemo.setValue("小黑: " + random.nextInt(1000));
}
});
}
// 分配180个读操作
for (int i = 0; i < 180; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
readWriteDemo.getValue();
}
});
}
// 关闭线程池
pool.shutdown();
while (!pool.isTerminated()){
}
Long end = System.currentTimeMillis();
System.out.println("不使用读写锁用时:" + (end - start));
}
}
七、线程安全的集合
①:问题演示
package com.example.arrays;
import java.util.ArrayList;
public class Demo1 {
public static void main(String[] args) {
// 1.创建arrayList
ArrayList<String> arrayList = new ArrayList<>();
// 2.创建线程
for (int i = 0; i < 20; i++) {
int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
for (int i1 = 0; i1 < 10; i1++) {
arrayList.add(Thread.currentThread().getName() + "==" + temp);
System.out.println(arrayList.toString());
}
}
}).start();
}
}
}
②:使用Collections中的工具类
③: 使用CopyOnWriteArrayList
案例1
package com.example.arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
public class Demo1 {
public static void main(String[] args) {
// 1.创建CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 2.创建线程
for (int i = 0; i < 20; i++) {
int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
for (int i1 = 0; i1 < 10; i1++) {
list.add(Thread.currentThread().getName() + "==" + temp);
System.out.println(list.toString());
}
}
}).start();
}
}
}
案例2
package com.example.arrays;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo2 {
public static void main(String[] args) {
// 创建集合
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
// 创建任务
for (int i = 0; i < 5; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
for (int i1 = 0; i1 < 10; i1++) {
String str = Thread.currentThread().getName() + new Random().nextInt(100);
list.add(str);
System.out.println(str);
}
}
});
}
// 关闭线程池
pool.shutdown();
while (!pool.isTerminated()){}
System.out.println("集合大小为:"+list.size());
}
}
④:CopyOnWriteArraySet
package com.example.arrays;
import java.util.concurrent.CopyOnWriteArraySet;
public class Demo3 {
public static void main(String[] args) {
CopyOnWriteArraySet<String> list = new CopyOnWriteArraySet<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("A");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
}
}
⑤:Queue接口(队列)
package com.example.arrays;
import java.util.LinkedList;
import java.util.Queue;
public class Demo4 {
public static void main(String[] args) {
// 创建集合
Queue<String> queue = new LinkedList<>();
// 添加元素
queue.add("苹果");
queue.add("香蕉");
queue.add("葡萄");
queue.add("橘子");
queue.add("榴莲");
// 获取第一个元素不删除
System.out.println(queue.peek());
System.out.println("======================");
System.out.println("元素个数为:"+queue.size());
int size = queue.size();
for (int i = 0; i < size; i++) {
System.out.println(queue.poll()); // 出队
}
System.out.println("元素个数为:"+queue.size()); // 出队后元素个数为0
}
}
⑥:ConcurrentLinkedQueue的使用
package com.example.arrays;
import java.util.concurrent.ConcurrentLinkedDeque;
public class Demo5 {
public static void main(String[] args) throws InterruptedException {
// 创建集合
ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();
// 创建任务
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 5; i++) {
deque.offer(i);
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 6; i <= 10; i++) {
deque.offer(i);
}
}
});
// 启动线程
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("----------出队----------");
int size = deque.size();
for (int i = 0; i < size; i++) {
System.out.println(deque.poll());
}
}
}
⑦:BlockingQueue接口(阻塞队列)
> 案例1:
package com.example.arrays;
import java.util.concurrent.ArrayBlockingQueue;
public class Demo6 {
public static void main(String[] args) throws InterruptedException {
// 创建一个有界队列,添加元素
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
// 添加元素
queue.put("a");
queue.put("b");
queue.put("c");
queue.put("d");
queue.put("e");
System.out.println("已经添加了5个元素~");
queue.put("f");
System.out.println("已经添加了6个元素~");
}
}
案例2 生产者和消费者
package com.example.arrays;
import java.util.concurrent.ArrayBlockingQueue;
public class Demo7 {
public static void main(String[] args) {
// 创建线程
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(6);
// 创建两个线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
try {
queue.put(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "生产了第 " + i + "块面包");
}
}
}, "小黑");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "消费了第 " + i + "块面包");
}
}
}, "小白");
// 启动线程
t1.start();
t2.start();
}
}
⑧:ConcurrentHashMap 线程安全集合
package com.example.arrays;
import java.util.concurrent.ConcurrentHashMap;
public class Demo8 {
public static void main(String[] args) {
// 创建集合
ConcurrentHashMap<String,Integer> hashMap = new ConcurrentHashMap<>();
// 使用多线程添加数据
for (int i = 0; i < 6; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10; j++) {
hashMap.put(Thread.currentThread().getName(),j);
System.out.println(hashMap);
}
}
}).start();
}
}
}