多线程详解
多线程详解
- 创建线程方式1:继承Thread类
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
public class TestThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
TestThread testThread01 = new TestThread();
//start方法拉起一个线程,两个程序交错执行,cpu安排调度
testThread01.start();
//run方法顺序执行
//testThread01.run();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程----" + i);
}
}
}
- 创建线程方式2:实现Runnable接口
- 自定义线程类MyRunnable类实现Runnable接口
- 重写run()方法,编写线程执行体
- 创建Thread对象,创建MyRunnable对象作为Thread对象的入参,调用start()方法启动线程
public class TestThread02 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("我在看runnable代码"+i);
}
}
public static void main(String[] args) {
TestThread testThread01 = new TestThread();
//start方法拉起一个线程,两个程序交错执行,cpu自动调度
new Thread(testThread01).start();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习runnable多线程----" + i);
}
}
}
-
多个线程操作同一个对象(买火车票)
-
callable实现要重写call方法,有返回值
静态代理
- 静态代理模式总结:
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实角色
- 好处:
- 代理对象可以做很多真实对象做不了的事情
- 真实对象专注做自己的事情
案例:
public class StaticProxy {
public static void main(String[] args) {
You you = new You();
// new Thread( ()-> System.out.println("我爱你") ).start();
WeddingCompany weddingCompany = new WeddingCompany(you);
weddingCompany.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真实角色,你去结婚
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("秦老师要结婚了!");
}
}
//代理角色,帮助你结婚
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany (Marry target){
this.target = target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();
after();
}
public void before(){
System.out.println("布置婚礼现场");
}
public void after(){
System.out.println("支付尾款");
}
}
Lambda表达式
- 函数式接口(Functional Interface):
- 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
- 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象。
- 有了函数式接口才能使用lambda表达式
- lambda简化:
- 简化过程:外部类-->静态内部类-->局部内部类-->匿名内部类-->lambda表达式
- (参数列表)->{//参数列表可以继续省掉类型声明,一个形参可以省略括号,方法体只有一句可以省略
/*
推导lambda表达式
*/
public class TestLambda1 {
//3.静态内部类
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
public static void main(String[] args) {
ILike iLike = new Like();
iLike.lambda();
iLike = new Like2();
iLike.lambda();
//4.局部内部类
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
iLike = new Like3();
iLike.lambda();
//5.匿名内部类
iLike = new ILike(){
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
iLike.lambda();
//6.用lambda简化
iLike = () -> {
System.out.println("i like lambda5");//单行输出
};
iLike.lambda();
//
}
}
//1.定义一个函数式接口
interface ILike{
void lambda();
}
//2.实现类
class Like implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
输出:
i like lambda
i like lambda2
i like lambda3
i like lambda4
i like lambda5
守护线程
- 线程分为用户线程和守护线程(daemon)
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录操作日志,监控内存,垃圾回收等待
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
thread.setDaemon(true);//默认false表示用户线程,正常的线程都是用户线程
thread.start();
new Thread(you).start();
}
}
class God implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("上帝保佑者你。。。");
}
}
}
class You implements Runnable {
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生都开心的活着。。。第" + i + "天");
}
System.out.println("goodbye,the world...");
}
}
- 不安全集合ArrayList<>()通过加锁实现安全
import java.util.ArrayList;
//synchronized(obj){} 默认给当前对象this上锁
public class UnSafeList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
//手动给list加锁
synchronized (list){
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
- 安全集合CopyOnWriteArrayList<>() 安全的,通过volatile关键字保证唯一,transient保证序列化的
import java.util.concurrent.CopyOnWriteArrayList;
//测试JUC安全类型的集合CopyOnWriteArrayList
public class TestJUC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
Lock(锁)
-
从JDK5.0开始,Java提供了更强大的线程同步机制--通过显示定义同步锁对象来实现同步。同步锁使用Lock对象充当
-
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
-
ReentrantLock(可重入锁),它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可显式加锁、释放锁。
//测试Lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable {
int ticketNums = 10;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();//加锁
if (ticketNums > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
} else {
break;
}
} finally {
lock.unlock();//解锁
}
}
}
}
- synchronized和Lock的对比:
- Lock是显式锁(手动开启和关闭锁,别忘记关闭),synchronized是隐式锁,出了作用域自动释放
- Lock只有代码块锁,synchronized有代码块锁和方法锁
- 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好地扩展性(提供更多的子类)
- 优先使用顺序:Lock >同步代码块(已经进入方法体,分配了相应资源)>同步方法(在方法体之外)
生产者消费者模式(一个问题)
package com.yunni.thread;/**
* @author niyun
* @date 2021/3/18 19:38
*/
import java.time.Duration;
import java.time.LocalTime;
//测试:生产者消费者模型
//生产者 , 消费者 , 产品 , 缓冲区
public class TestPC {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者
class Productor extends Thread{
SynContainer container;//成员变量
public Productor(SynContainer container){
this.container = container;
}
//生产
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("生产了"+i+"只鸡");
}
}
}
class Consumer extends Thread{
SynContainer container;//成员变量
public Consumer(SynContainer container){
this.container = container;
}
//消费
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Chicken ch = container.pop();
System.out.println("消费了第"+ch.id+"只鸡");
}
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
class SynContainer{
//需要一个容器
Chicken[] chickens = new Chicken[10];
//容器计数器
int count = 0;
//生产者放入产品
public synchronized void push(Chicken chicken) {
//如果容器满了,就需要等待消费者消费
if (count==chickens.length){
//通知消费者消费,成产等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有满,我们就需要丢入产品
chickens[count]=chicken;
count++;
//可以通知消费者消费了
this.notifyAll();
}
public synchronized Chicken pop() {
//如果容器空了,就需要等待生产者生产
if (count==0){
//通知生产者生产,消费等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Chicken chicken = chickens[count];
//可以通知生产者生产了
this.notifyAll();
return chicken;
}
}
浙公网安备 33010602011771号