多线程笔记

线程创建的方式

1、继承Thread类
2、实现Runnable接口
3、实现Callable接口

实现Runnable

1、定义MyRunnable类实现Runnable接口
2、实现run()方法,编写线程执行体
3、创建线程对象,调用start()方法启动线程

public class TestThread3 implements Runnable {
    //重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();
        //创建线程对象,通过线程对象来开启我们的线程,代理
        new Thread(testThread3).start();
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习"+i);
        }
    }
}

继承Thread类

启动线程:子类对象.start()

TestThread3 testThread3 = new TestThread3();
testThread3.start();

实现Runnable接口

启动线程:传入目标对象+Thread对象.start()

TestThread3 testThread3 = new TestThread3();
new Thread(testThread3).start();

并发问题

//获得当前线程
Thread.currentThread();
//获得当前执行线程的名字
Thread.currentThread().getName()
//模拟延时
Thread.sleep(x);//x:毫秒值

Callable

 1. 实现Callable接口,需要返回值类型
 2. 重写call()方法,需要抛出异常
 3. 创建目标对象
 4. 创建执行服务
	ExecutorService ser = Executors.newFixedThreadPool(x);//x:线程数
 5. 提交执行:Future<Boolean> result1 =ser.submit(t1);//t1:对象名
 6. 获取结果:boolean r1 = result1.get();
 7. 关闭服务:ser.shutdownNow();

Lamda表达式

函数式接口

任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口

Lambda表达式

( ) - > { };

  • Lambda表达式只能有一行代码的情况下此才能简化成一行,如果有多行,那么就用代码块包裹。
  • 前提是接口为函数式接口
  • 多个参数也可以去掉参数类型,要去掉需要全部去掉,必须加上括号

线程状态

在这里插入图片描述

线程方法

setPriority(int newPriority)//更改线程的优先级
static void sleep(long millis)//休眠
void join()//等待该线程终止,插队
static void yield()//暂停当前正在执行的线程对象,并执行其他线程,礼让不一定成功,让cpu重新调度,看cpu
void interrupt()//中断线程
boolean isAlive()//测试线程是否处于活动状态

停止线程

  • 不推荐使用JDK提供的stop()/destroy()方法【已废弃】
  • 推荐线程自己停止下来
  • 建议使用一个标志位进行终止变量当flag=false,则终止线程运行

线程休眠

sleep存在异常InterruptedException
模拟网络延时:放大问题的发生性

Date date = new Date(System.currentTimeMillis());//获取系统当前时间
new SimpleDateFormat("HH:mm:ss").format(date);//时间格式化

每个对象都有一个锁,sleep不会释放锁;

线程状态

Thread.State state = new Thread().getState();//观察状态
Thread.State.TERMINATED;//线程终止状态

线程优先级

getPriority();//获取优先级
setPriority(int x);//改变优先级x:1——10之间
setPriority(Thread.MAX_PRIORITY);//设置最大优先级10

守护(daemon)线程

线程分为用户线程守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕

setDaemon(true);//设置守护线程 

并发

线程同步其实就是一种等待机制
对象的等待池形成队列
保证线程安全性需要队列+锁

锁(synchronized)

弊端

一个线程持有锁会导致其他所有需要次锁的线程挂起
会影响程序性能
如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题

同步方法
public synchronized void method(int args){}
//缺陷:若将一个大的方法申明为synchronized将会影响效率
同步块
synchronized(obj){}//obj是需要增删改的对象
//JUC安全类型集合
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();//安全集合,无需添加同步锁

死锁

多个线程互相抱着对方需要的资源,然后形成僵持

Lock(锁)

可重入锁 ReentrantLock类实现了Lock

class A{
	private final ReentrantLock lock = new ReentrantLock();
	public void m(){
		lock.lock();
		try{
			//保证线程安全的代码
		}finally{
			lock.unlock();
			//如果同步代码有异常,要将unlock()写入finally语句块
		}
	}
}

synchronized 与Lock的对比

  1. Lock是显式锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放
  2. Lock只有代码块锁,synchronized有代码块锁和方法锁
  3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的拓展性(提供更多的子类)
  4. 有限使用顺序
    Lock > 同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)

线程协作

线程通信

wait()//表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁
wait(long timeout)//指定等待的毫秒数
notify()//唤醒一个处于等待状态的线程
notifyAll()//唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度
//注意:均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException

生产者消费者模型

利用缓冲区解决:管程法

package com.kuang.demo4;
//生产者、消费者、产品、缓冲区(生产、消费)
public class TestPC {
    public static void main(String[] args) {
        SynContiner continer = new SynContiner();
        new Product(continer).start();
        new Customer(continer).start();
    }
}
//产品
class Chicken{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}

//生产者
class Product extends Thread{
    SynContiner continer;
    public Product(SynContiner continer) {
        this.continer = continer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            continer.push(new Chicken(i));
            System.out.println("生产了"+i+"只鸡");
        }
    }
}
//消费者
class Customer extends Thread{
    SynContiner continer;
    public Customer(SynContiner continer) {
        this.continer = continer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了"+continer.pop().id+"只鸡");
        }
    }
}

//缓冲区
class SynContiner implements Runnable{
    //定义产品数量
    int count = 0;
    //定义容器大小
    Chicken[] chickens = new  Chicken[10];
    @Override
    public void run() {

    }
    //生产方法
    public synchronized void push(Chicken chicken){
        if (count==10){
            //如果超过十个进入等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
            //低于10个可以继续生产
            chickens[count]=chicken;
            count++;
            notifyAll();

    }
    //消费方法
    public synchronized Chicken pop(){
        if (count==0){
            //如果没有产品,进入等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
            count--;
            Chicken chicken = chickens[count];
            notifyAll();
            return chicken;


    }
}

信号灯法,标志位解决

package com.kuang.demo4;

public class TestMark {
    public static void main(String[] args) {
        //新建节目
        TV tv = new TV();
        //开启线程
        new Player(tv).start();
        new Watcher(tv).start();

    }
}
//演员
class Player extends Thread{
    TV tv;

    public Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i%2==0){
                tv.make("收看快乐大本营");
            }else {
                tv.make("收看广告");
            }
        }
    }
}
//观众
class Watcher extends Thread{
    TV tv;

    public Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.see();
        }
    }
}
//节目
class TV{
    String voice;//表演的节目
    boolean flag = true;//标志位
    //表演方法
    public synchronized void make(String voice){
        if (!flag){//等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }
            System.out.println("表演节目"+voice);
            this.notifyAll();
            this.flag = !this.flag;
            this.voice = voice;



    }
    //观看方法
    public synchronized void see(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        this.notifyAll();
        this.flag = !this.flag;

        System.out.println("观看节目");
    }
}

线程池

//1、创建服务,创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);//参数为线程池大小
//2、执行
service.execute(new MyThread());//MyThread():Runnable接口实现类
//3、关闭链接
service.shutdown();
package com.kuang.demo4;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
    public static void main(String[] args) {
        //创建服务,创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //关闭链接
        service.shutdown();
    }

}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

在这里插入图片描述

线程总结

package com.kuang.demo4;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class TestNew {
    public static void main(String[] args) {
        MyThread1 myThread1 = new MyThread1();
        myThread1.start();
        MyThread2 myThread2 = new MyThread2();
        new Thread(myThread2).start();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();
        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
//继承Thread类
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
//实现Runnable接口
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
//继承Callable接口
class MyThread3 implements Callable{
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        return 100;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值