day21
一、线程
1.程序:一个固定逻辑与数据的集合就叫程序 例子:贪吃蛇
2.cpu:中央处理器 用来协调程序与硬件的工作
3.并发与并行:
并发(高并发):在同一个时间,执行两个或者两个以上的程序,单核cpu交互执行
(误区:不是同时执行,是交替执行)
并行:在同一时刻,执行两个或者以上的程序的时候,多核cpu一起执行 (目前的电脑都是多核的)
4.进程和线程:
进程:运行在内存中的程序叫进程 例子:idea
线程:通向cpu的执行路径叫线程
5.分类:
单线程:只有一条通向cpu的执行路径
多线程:多条通向cpu的执行路径
单线程:
多线程:
1.1 主线程:
1.2 线程的第一种创建方式
1.创建的步骤:
A.定义一个类继承:Thread
B.重写run()方法,执行线程操作
C.实例化这个线程的对象
D.调用Start()方法开启线程
代码 -测试类:
package com.lt.demo11;
public class Teat01 {
public static void main(String[] args) {
MyThread m = new MyThread();
m.start();
}
}
代码-定义类:
package com.lt.demo11;
public class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
1.3 线程的调度方法
1.线程的配调的方式:分配式调度和抢占式调度
2.分配式调度:多个线程执行任务的时间,都是平均分配的,每一个线程执行的时间都是相等的
3.抢占式调度:线程的优先级越高,抢占cpu的执行权越高,线程抢到cpu的执行权,优先执行
注意点:Java的多线程就是抢占式调度(比武招亲)
原因分析:
1.4 线程的内存图:
二、线程的方法
2.1 线程的一些方法
1.获取线程的名称的方法:
public final String getName() 返回该线程的名称
public static Thread currentThread() 返回对当前正在执行的线程对象的引用
2.改变线程的名称的方法;
public final void setName(String name) 改变线程名称
public Thread(String name) 通过构造方法设置线程的名称(这个Thread里面需要有参构造)
3.线程休眠的方法:
public static void sleep(long millis) 设置线程休眠,时间单位是毫秒
4.守护线程:
A.守护其他线程 守护其他线程执行完操作(Java里面的gc垃圾回收器就是一个守护线程)
B.守护线程的死亡:被守护的线程执行完操作或守护的线程死亡,那么守护线程才会死亡
C.一般的守护线程都是守护主线程
5.线程的优先级:
常量:
A.public static final int MAX_PRIORITY 线程可以具有的最高优先级
B.public static final int MIN_PRIORITY 线程可以具有的最低优先级
C.public static final int NORM_PRIORITY 分配给线程的默认优先级
注意点:1.线程的最高优先级是10 最低优先级是1 范围:1-10
2.线程优先级越高表示线程抢到了,但是不一定执行
2.2 线程的第二种创建方式
1.步骤:
A.定义一个类,实现Runnble接口
B.实现里面的run()方法
C.实例化线程对象:Thread 传递一个参数Runnble的实现类
测试类:
package com.lt.demo10;
public class Test01 {
public static void main(String[] args) {
//实例化MyRunnble类
MyRunnble m = new MyRunnble();
//实例化Thread类
Thread t = new Thread(m);
t.start();
}
}
定义类:
package com.lt.demo10;
public class MyRunnble implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
2.3 使用内部类里创建线程
package com.lt.demo10;
public class Test02 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}.start();
}
}
三、线程通信(重点)
3.1 案例:
需求分析:
A.每一个窗口就是一个线程 使用线程来表示多窗口售票
B.数据共享 使用第二种方式来创建线程
C.定义一个变量来表示票数
D.循环售票
定义类:
package com.lt.demo12;
public class MyRunble implements Runnable{
private int count=100;
@Override
public void run() {
while (count>=0){
if (count>0){
System.out.println(Thread.currentThread().getName()+"\t"+count);
count--;
}
}
}
}
测试类:
package com.lt.demo12;
public class Test01 {
public static void main(String[] args) {
MyRunble r =new MyRunble();
Thread t1 = new Thread(r);
t1.start();
Thread t2 = new Thread(r);
t2.start();
Thread t3 = new Thread(r);
t3.start();
}
}
上面的代码出现错误:
产生问题原因:
3.2 第一种解决方法:同步代码块
1.语法:
synchronized(锁对象){
可能发生错误的代码
}
2.注意点:
A.锁对象可以是任意的对象
B.所有的线程锁的对象必须是同一个是对象
3.作用:
解决数据共享安全问题
优化代码:
package com.lt.demo12;
public class MyRunble implements Runnable{
private int count=100;
private Object obj = new Object();
@Override
public void run() {
while (count>=0){
synchronized (obj){
if (count>0){
System.out.println(Thread.currentThread().getName()+"\t"+count);
count--;
}
}
}
}
}
测试类不变
3.3 解决问题分析
3.4 第二种方法-同步方法
1.语法:
访问修饰符 synchronized 返回值类型 方法的名称(参数列表){
方法体
return 返回值
}
2.说明:同步方法可以是普通的方法,也可以是静态的方法
3.解释:
A.成员方法的锁的1对象是this
B.静态方法的锁的对象是当前类的class对象
优化代码:
package com.lt.demo12;
public class MyRunble implements Runnable{
//定义一个数来表示票的数量
private static int count=100;
//定义一个锁对象
private Object obj = new Object();
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (count>=0){
showInfo();
}
}
public static synchronized void showInfo(){
if (count>0){
System.out.println(Thread.currentThread().getName()+"\t"+count);
count--;
}
}
}
测试代码不变
3.5 第三种解决方法
1.使用Lock(接口)
A.Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
B.此实现允许更灵活的结构
2.实现类:ReentrantLock
3.方法:
void lock() 获取锁
void unlock() 释放锁
优化的代码:
package com.lt.demo12;
public class Test01 {
public static void main(String[] args) {
MyRunble r =new MyRunble();
//第一个线程
Thread t1 = new Thread(r);
t1.start();
//第二个线程
Thread t2 = new Thread(r);
t2.start();
//第三个线程
Thread t3 = new Thread(r);
t3.start();
}
}
四、死锁
1.死锁:A占用B的锁对象 B占用A的锁对象 互不谦让 两个现场1处于等待状态,形成死锁
2.例子:
两个人在寝室,宿舍里只有一双拖鞋,A占领左拖鞋,B占领右拖鞋 两个人都要出去买东西,两个都不给对方另外一只拖鞋,都出不去
A成员:
package com.lt.demo13;
public class AMyRunnble implements Runnable {
@Override
public void run() {
synchronized (Shoe.LEFT){
System.out.println("A占领左拖鞋");
synchronized (Shoe.RIGHT){
System.out.println("A占领右拖鞋");
}
}
}
}
B.成员:
package com.lt.demo13;
public class BMyRunnble implements Runnable {
@Override
public void run() {
synchronized (Shoe.RIGHT){
System.out.println("B占领右拖鞋");
synchronized (Shoe.LEFT){
System.out.println("B占领左拖鞋");
}
}
}
}
定义类:
package com.lt.demo13;
public class Shoe {
public static final String LEFT="LEFT";
public static final String RIGHT="RIGHT";
}
测试类:
package com.lt.demo13;
public class Test01 {
public static void main(String[] args) {
//实例化A成员
AMyRunnble amy = new AMyRunnble();
Thread t1 = new Thread(amy);
t1.start();
//实例化B成员
BMyRunnble bmy = new BMyRunnble();
Thread t2= new Thread(bmy);
t2.start();
}
}
测试结果:
|