进程:正在运行的程序
实习厅进行资源分配和调用的独立单位
每一个进程都有他的内存空间和系统资源。
线程:是进程中单个顺序控制流,
单线程:一个进程如果只有一条执行路径,则为单线程程序
多线程:一个进程如果有多条执行路径,多线程程序
多线程实现Thread类线程是程序中执行的线程,允许应用程序同时执行多个执行线程。
JAVA中线程的定义分为继承Thread父类和实现接口Runnable两种。需要一下的几个步骤
一、Thread类1.创建线程
2.重写线程中的run()方法
3.调用线程对象中的start()方法,启动线程执行
4.启动后,不等于线程执行了,当线程执行满足条件后,才能执行run()方法。
run()方法是用来封装被线程执行的代码
run()封装执行的代码直接调用
start()启动线程;由JVM调用线程的run()方法
设置和获取线程名称因为有多个数据 不知道数据是属于哪一个的所以需要获取线程的名称
String getName():返回此线程的名称
setName(String name):将此线程的名称更改为设置的名称
线程调度两种调度模型:
分时电镀模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用的时间片
抢占式调度模型:优先让优先级高的线程使用CPU,如果优先级相同,则随意地选择一个,优先级高的获取的时间多一些
多线程执行是有随机性的
getPriority()得到优先级 setPriority()设置优先级
默认优先级是5,最大优先级是10 最小是1,
线程优先级高仅仅带边过去的时间片几率高,但是要在次数多的时候才能看到效果 每次的运行结果都是随机的。
线程控制sleep(long millins)使当前正在执行的线程停留指定的毫秒数
join()等待这个线程死亡
setDaemon(boolean on) 将此线程标记为守护线程,当运行的线程都是守护线程时,java虚拟机将退出。守护主线程,如果主线程没有了 则守护线程也缓缓的退出
线程生命周期创建线程对象 调用start()方法 有资格执行还没有执行权 抢到执行权后 如果被其他优先级抢到执行权 则在进行抢执行权 开始运行 运行时可能会有sleep()或者其他的阻塞方法 则会进入阻塞状态 直到sleep时间结束或者阻塞方式结束 如果run()方法的代码结束 或者调用start()方法 则线程死亡。
二、实现接口Runnable1.定义一个例如RunableDemo类实现Runable接口
2.在类中重写run方法
3.创建RunnableDemo类对象
4.创建Thread类的对象,把RunnableDemo对象作为构造方法的参数
5.启动线程
Thread(Runnable target, String name)
分配一个新的 Thread对象。可以有名字
Thread(Runnable target)
分配一个新的 Thread对象。
卖票功能共有100张票,有三个窗口卖票。
1.定义一个类实现Runnable接口,
2.在Ticket类中重写run方法:
判断票数大于0,就卖票,并告诉是哪个窗口卖的
卖了票总票数减一
票没有了,可以用死循环让卖票的动作执行
3.定义一个测试类,创建Ticket类对象,创建三个Thread类对象将Ticket类作为参数传递。
可能会出现问题:
1.用sleep()方法三个窗口可能同时出售一张票 原因:
在t1线程休息例如100毫秒时,t2抢到了CPU的执行权,t2线程就开始执行,执行到sleep时在休息100毫秒,t3就抢到了CPU的执行权,执行到sleep时在休息100毫秒。
线程按照顺序醒过来后 t1抢到CPU执行权,在控制台输出
t2抢到执行权,在控制台输出。t3抢到执行权,在控制台输出,就执行了卖同一张票的操作。
2.出现负数的票
在出售卖票时,t1抢到CPU执行权,在控制台输出,立刻执行ticket--操作时 等等 就会出现票数负数的情况
线程的执行具有随机性。
出现问题1.是否是多线程环境
2.是否有共享数据
3.是否有多条语句操作共享数据
怎样解决?
让程序没有安全问题的环境
把多条语句操作共享数据的代码锁起来,让任意时刻只能有一个线程执行即可 JAVA提供了同步代码块方式解决。
同步代码快锁多条数据操作共享数据,可以使用同步代码块实现
synchronized(任意对象){//相当于给代码加锁了,任意对象就可以看成是一把锁
多条语句操作共享数据代码}
同步方法把synchronized关键字加到方法上
格式为 synchronized返回值类型 方法名(方法参数){}
同步方法的锁对象为this
同步静态方法:把synchronized加到静态方法上
修饰符 static synchronized 返回值类型 方法名(方法参数){}
同步静态方法的锁对象是
类名.class
线程安全的类StringBuffer
线程安全,可变的字符序列。从版本JDK 5开始,这个类别已经被一个等级类补充了,这个类被设计为使用一个线程StringBuilder 。 StringBuilder应该使用StringBuilder类,因为它支持所有相同的操作,但它更快,因为它不执行同步。StringBuilder没有锁 不安全
Vector
从Java 2平台v1.2,这个类被改造为实现List接口,使其成为成员Java Collections framework 。 与新集合实现不同, Vector是同步的。 如果不需要线程安全的实现,建议使用ArrayList代替Vector 。
Hashtable
该类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键值或值。
从Java 2平台v1.2,这个类被改造为实现Map接口,使其成为成员Java Collections framework 。 与新的集合实现不同, Hashtable是同步的。 如果不需要线程安全的实现,建议使用HashMap代替Hashtable 。
以下三种类是安全的:
StringBuilder sb=new StringBuilder(); VectorLock锁vc=new Vector<>(); Hashtable hn=new Hashtable<>();
提供了获得锁和释放锁的方法
void lock():获得锁
void unlock():释放锁
生产者消费者模式
主要包含了两个线程
一类是生产者线程用于生产数据
一类是消费者线程用于消费数据
为了解耦生产者消费者关系,通常会采用共享的数据区域,就像是一个仓库。
生产者生产数据之后放置在共享数据区中,并不需要关心消费者的行为
消费者只需要从共享数据区中获取数据,并不需要关心生产者的行为。
为了体现生产和消费过程中的等待和唤醒,有几种方法
void wait() 导致当前线程等待,直到另一个线程调用该对象的notify()方法或者notifyAll()方法
void notify()唤醒正在等待对象监视器的单个线程
void notifyAll()唤醒正在等待对象监视器的所有线程
送奶类:奶箱类:定义一个成员变量,表示第几瓶奶,提供存储牛奶和获得牛奶的操作
生产者类:实现Runnable接口,重写run()方法,调用存储牛奶的操作
消费者类:实现Runnable接口,重写run()方法,调用获取牛奶的操作
测试类:里面有main方法,有以下的步骤
1.创建奶箱对象,这是共享数据区域
2.创建生产者对象,把奶箱对象作为构造方法参数传递,在这个类中要调用存储牛奶的操作
3.创建消费者对象,把奶箱对象作为构造方法参数传递,在这个类中要调用获取牛奶的操作
4.创建两个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递。
5.启动线程
代码之后会发布



