1.多线程
例如:一个短视频,一个线程复制管理视频,一个线程负责管理声音,一个线程负责管理弹幕
进程:Process,程序一旦开始运行就是是一个进程
线程:Thread,一个程序运行后,里面就包含了多个线程
真正的多线程是指有多个cpu,即多核。如果是模拟的多线程,即只有一个cpu,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错误
2.线程的创建
1.继承Thread类
线程不一定立即执行,听从cpu的安排,交替执行
//实现步骤
1.继承Thread
2.重些run方法
3.对象. start()启动线程
public class StartThread extends Thread
{
@Override
public void run()
{
}
}
StartThread a=new StartThread();
a.start()
2.实现Runnable接口
接口实现类对象能被多个线程使用
1.实现接口
2.编写线程方法
3.开启线程,通过实现Runnable接口来创建线程,启动线程时需要通过Thread对象。
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
并发问题:
3.实现Callable接口
3.静态代理
使用步骤
1.需要代理对象、实际对象,以及一个抽象接口
2.代理对象、实际对象都要实现接口
3.代理对象中创建构造方法,方法参数为接口类对象
4.在代理对象中定义抽象接口类对象来接收构造方法的参数对象
5.在代理对象中接口的实现方法中,用接收到的变量接口对象调用实现的接口方法
逻辑,通过代理对象的有参构造,将实际对象以参数的形式传递到代理类中,然后在代理类接口的实现方法中,调用实际类中的实现方法
4.线程停止
1.设立外部标志位,定义一个公开的方法,通过改变标志位来结束进程
5.线程休眠
应用
1.模拟网络延时
通过延时可以发现多线程中出现的问题,如数据同步性
2.倒计时
每个对象都有一把锁,sleep不回释放锁
6.线程礼让
Thread.yield()
正在进行的线程,由运行态转为就绪态,然后由cpu在就绪态中选择另一个线程,礼让不一定百分百成功
7.线程强制执行
线程插队,强制执行插队的线程
8.观测线程的状态
Thread.getState()
线程的状态
1.创建
2.就绪
3.执行
4.阻塞
5.结束,线程一旦结束,就不能再被使用
9.线程的优先级
thread.setPriority()
10.守护线程
监控用户线程,用户线程结束,守护线程也结束
thread.setDaemon()
11.线程同步
并发:同一个对象被多个线程同时操作,如:秒杀,抢票
解决线程的不安全性:队列+锁,解决数据安全性
synchronized
//修饰代码块
synchronized(this){} //修饰当前类
synchronized(类.class){}//修饰其他类
//修饰方法
1.修饰静态方法
2.修饰非静态方法案例代码:
class Thick implements Runnable
{private int num=10;Boolean flag=true;@Overridepublic void run(){try {buy();} catch (InterruptedException e) {throw new RuntimeException(e);}}public void buy() throws InterruptedException {while (flag){Thread.sleep(200);if (num>0)synchronized (this){System.out.println(Thread.currentThread().getName()+"买到了第"+num--+"票");}else{flag=false;}}}public class CarThick {public static void main(String[] args) {Thick thick=new Thick();new Thread(thick,"张三").start();new Thread(thick,"李四").start();new Thread(thick,"王二狗").start();}
}
12.死锁
13.Lock锁
和synchronized
锁的作用一样,在线程同步的情况下,保证数据的原子性
ReentrantLock//可重入锁
private final ReentrantLock lock=new ReentrantLock();
lock.lock();//加锁,在数据发生改变的地方,加锁
lock.uplock;//解锁,完成数据改动后,把锁给下一个线程
14.生产者与消费者-线程通信
1.生产者
2.消费者
3.线程池
4.消费品
管程法
//线程池
class SynContainer{// 需要一个容器大小Bug[] bugs = new Bug[10];// 容器计算器int count = 0;// 生产者放入bugpublic synchronized void push(Bug bug){// 如果容器满了,就需要等待消灭bugif(count==bugs.length){// 通知消灭bug者消灭,生产bug等待try {//导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。this.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 如果没有满,我们就需要继续生产bugbugs[count] = bug;count++;// 可以通知消灭者消灭了this.notifyAll();// notifyAll唤醒正在等待对象监视器的所有线程。}// 消灭者消灭bugpublic synchronized Bug pop(){// 判断能否消灭if (count == 0){// 等待生产者生产,消灭者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 如果可以消灭count--;Bug bug = bugs[count];// 消灭完了,通知生产者生产this.notifyAll();try {System.out.println("通知生产者");Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return bug;}
//生产者
class Productor extends Thread{SynContainer container;public Productor(SynContainer container){this.container = container;}// 生产@Overridepublic void run() {for (int i = 0; i <=100; i++) {container.push(new Bug(i));System.out.println("生产了"+i+"个bug");}}
}//消费者
class Consumer extends Thread{SynContainer container;public Consumer(SynContainer container){this.container = container;}@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println("消灭了-->"+container.pop().id+"个bug");}}
}
//消费品
class Bug{int id;// bug编号public Bug(int id){this.id = id;}
}
//测试
public class ProviderAndConsumer
{public static void main(String[] args) {SynContainer container = new SynContainer();new Productor(container).start();new Consumer(container).start();}
}
15.线程池
避免重复的创建销毁线程,减少资源浪费,类似于数据库连接池