复习:
GUI : String,包装器,集合,泛型,反射
GridLayout : 网格布局
new GridLayout(3,3);
CardLayout : 卡片布局
每次添加到容器中的组件,当成卡片,
JPanel pan= new JPanel();
CardLayout c = new CardLayout();
pan.setLayout(c);
pan.add(new JButton());
pan.add(new JButton(),"卡片的名字");
c.show(pan,"卡片的名字")
Null 不要布局 ,乱放,
设置位置以后才能看见组件,
1,setSize();+setLaction();
2,setBounds(x,y,w,h);
Frame : BorderLayout
Panel : FlowLayout
new Panel(null);
JPanel p = new JPanel();
p.setLayout(null);
组件使用 :
项目下
ImageIcon icon = new ImageIcon("地址")
缩放
Image img= icon.getImage().getSI(w,h,Image.S_Fast);
icon.setImage(img);
JButton + JLabel
new JButton(icon);
new JLabel(icon);
//数据
DefaultTableMode dm = new DTM(Object[] tableHead,0);
new JTable(dm);
JScrollPane scroll = new JS(table);
事件 :
可能发生的事件 , 绑定代码
JButton but = new JButton();
but.addActionListener(new ActionListener(){
(ActionEvnet event){
事件源 = event.getSource();
}
});
javax.swing.Timer
new Timer(时间,new ActionListener(){
(ActionEvent evnet){
Timer t = event.getSource();
t.stop();
}
});
timer.start();
timer.stop();
绘画:
JPanel pan = new JPanel(){
//G 画笔
paintCom...(G g){
g.drawImage();
g.setColor(Color.red);
g.drawLine();
g.setColor(Color.blue);
g.drawLine();
}
};
0,进程
进程 : 每一个进程都有自己独立的内存空间,这个内存空间有操作系统分配。
360 : 进程
线程1 :安全监测
线程2 :垃圾清理
线程3 :病毒查杀
1,线程:一个进程中的一条执行流程
线程不可以脱离进程独立执行(计算机最小处理的就是进程)
可以理解线程是某一个进程下多条不同的流程互不影响的执行代码流程
线程特点:
在对应的进程内存空间中运行,线程可以共享同一块内存和系统资源
在java虚拟机进程中,执行程序代码的任务是由 线程 来完成的。
每当用java命令启动一个Java虚拟机进程时,Java虚拟机都会创建一个主线程。
该线程从程序入口main()方法开始执行。也就是main线程
计算机中机器指令的真正执行者是CPU,线程必须获得CPU的使用权,才能执行一条指令。
代码是执行某一个时间片
执行完成以后会停下来等
2,线程的分类:
2.1:前台线程(执行线程)
看得到
执行代码的线程
线程执行main-->main线程
只要有前台现在在执行,jvm就不会停。
2.2:后台线程(守护线程/精灵线程)
gc:
当 前台线程 结束 守护线程也会结束
注:每次写的main方法中代码是由一个主线程执行的
3,线程的使用:
3.1:使用线程去执行在非常耗时的代码
3.2:使用线程让多个代码同时执行
1 100
for(int i = 0;i<100;i++){
}
1 100
for(int i = 0;i<100;i++){
}
CPU执行代码,一个cpu 单核 单线程,
同一时刻只能执行一段代码
cpu --> 指令 --> 调度 --> 硬件资源
--> 指令 --> 调度
硬盘
1S 2分钟
4,线程的生命周期
4.1:新建: 新建了线程对象
4.1.1:一个类继承Thread类 重写run方法->得到了新的线程类
Thread t = new MyThread();
4.1.2:一个类实现接口Runnable重写run方法-->得到新的线程类
MyThread myt = new MyTeacher();
Thread t = new Thread(myt);
4.2:就绪:调用完start方法以后
t.start();
4.3:运行:线程得到cpu时间片以后执行代码
4.4:阻塞状态:代码暂停运行
4.4.1:挂起:sleep(毫秒);join();yield();
恢复为就绪状态:
sleep():睡觉时间完了
join();目标线程执行完毕
yield();让出cup执行权限立刻回到就绪状态
注: 不会释放锁资源
4.4.2:锁池等待 : 在run方法中执行了加锁的代码,但是锁被其他线程获取走了,当前线程就会到锁池等待.
恢复为就绪状态:
当其他线程释放锁资源,立刻回到就绪状态
4.4.3:等待池等待 : 当执行wait()方法以后就会到等待池等待
恢复为锁池等待
当其他线程执行了notify/notifyall方法的时候回从等待池回到锁池等待.
注: wait()方法会释放锁资源
4.5:死亡状态:当线程执行完run方法中所有代码就会变成死亡状态.
run方法执行完毕
龟兔赛跑:
100米
t|----------------
r|----------------
线程
每个线程操作自己的数据
isWin 是公共数据 static
run(){
while(nun<100){
if(isWin){
break;
}
..........
}
isWin = true;
syso(谁赢了)
}
火车卖票
k123 : 100票
窗口1 |----------
窗口2 |--------------
窗口3 |-------------
窗口4 |----
if(num>0){
}else{
break;
}
5. 线程调度
计算机通常只有一个CPU, 在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令。
所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。
在可运行池中,会有多个处于就绪状态的线程在等待CPU,Java虚拟机的一项任务就是负责线程的调度。
线程的调度是指按照特定的机制为多个线程分配CPU的使用权。有两种调度模型:
. 分时调度模型:让所有线程轮流获得CPU的使用权,并且平均分配每个线程占用CPU的时间片。
. 抢占式调度模型:优先让可运行池中优先级高的线程较多可能占用CPU(概率高),如果可运行池中线程的优先级相同,那么就随机选择一个线程,使其占用CPU。处于可运行状态的线程会一直运行,直至它不得不放弃CPU。Java虚拟机采用这种。
一个线程会因为以下原因而放弃CPU:
. Java虚拟机让当前线程暂时放弃CPU,转到就绪状态;
. 当前线程因为某些原因而进入阻塞状态;
. 线程运行结束;
线程的调度不是跨平台的,它不仅取决于Java虚拟机,还依赖于操作系统。
在某些操作系统中,只要运行中的线程没有阻塞,就不会放弃CPU;
在某些操作系统中,即使运行中的线程没有遇到阻塞,也会在运行一段时间后放弃CPU,给其他线程运行机会。
5,线程常用方法使用
5.0: t1.start();线程开始执行
线程只能启动一次
5.1: Thread.sleep(1000);//当前线程睡1000毫秒
(放弃cup执行权限)
5.2: Thread.currentThread();//获取当前正在执行的线程
5.3: t1.getName();//获取线程名
5.4: t1.setName("线程名");//设置线程名
5.5: t1.join();//当前线程(t1.join()这个代码在哪个线程里)等待t1线程执行完成以后再执行(当前线程,放弃cup执行权限)
5.6: this.yield();//当前线程让出cpu执行权限回到就绪状态
--------------------
5.7: this.notify();//随机唤醒一个线程-->等待池 //必须为锁对象调用,wait()也是
5.8: this.notifyAll();//唤醒所有线程
5.9: this.isAlive();//线程是否是活的
5.10: interrupt();//设置线程中断状态标识位-->中断状态:true
5.11: isInterrupted();//查看返回线程的中断状态标识位 true:有线程要中断当前线程
//不会清除线程的中断状态
5.12: interrupted();//返回线程的中断状态标识位 true:有线程要中断当前线程
//清除线程的中断状态
5.13: setDaemon(true);//把新建状态的线程设置为守护线程。只能是新建状态。
6,线程同步 : synchronized
线程不安全:多个线程操作同一份数据就会导致线程不安全问题
线程同步就是解决这个问题的
通过加锁就可以达到线程同步
6.1:synchronized关键字可以出现的地方
6.2:synchronized(锁){//线程同步的代码}
6.3:public synchronized void say(){}-->this
6.4:public static synchronized void say(){}-->Hello.class
注意问题: 多个线程对象使用的锁是不是同一把锁
是,多个线程 对于 锁 上的代码按顺序运行
否, 多个线程 对于 锁 上的代码任意运行
补充:
synchronized实现可见性
可以实现互斥锁(原子性),即同步。但很多人都忽略其内存可见性这一特性
JMM关于synchronized的两条规定:
线程解锁前,必须把共享变量的最新值刷新到主内存中
线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁)
线程解锁前对共享变量的修改在下棋甲所示对其他线程可见
7,线程通信
使用 锁对象.wait(); 会释放锁资源 放弃cup执行权限
锁对象.notify();
锁对象.notifyAll();
8,线程的死锁
A线程需要的锁被B线程获取
B线程需要的锁被A线程获取
9,线程的让步
yield()方法
Thread.yield()静态方法,
如果此时具有相同优先级的其他线程处于就绪状态,那么yield()方法将把当前运行的线程放到可运行池中并使另一个线程运行。如果没有相同优先级的可运行线程,则yield()方法什么也不做。
yield()只会给相同优先级或者更高优先级的线程一个运行的机会。
yield()转到就绪状态;
yield()不抛任何异常
yield()并不常用。
龟兔赛跑:
package com.briup.ch15.work15;
public class RabbitAndTurtle extends Thread{
private int num;//两个线程的num是不共享的
private static boolean flag=false;//得把最终设置为static,这样它俩共享这个数据,所以就可以在一个flag为true时跳出这个循环
public RabbitAndTurtle(String name) {
super(name);
}
public void run() {
while(num<=100) {
if(flag)
break;
if(Thread.currentThread().getName().equals("Rabbit")) {
if(Math.random()<0.3) {
num+=2;
System.out.println("Rabbit:"+num);
if(num==100) {
break;
}
}Thread.yield();
}else if(Thread.currentThread().getName().equals("Turtle")) {
if(Math.random()>0.3) {
num++;
System.out.println("\t"+"Turtle:"+num);
if(num==100) {
break;
}
}Thread.yield();
}
}
if(num==100) {
System.out.println(Thread.currentThread().getName()+"WIN");
flag=true;
}
}
}
package com.briup.ch15.work15;
public class Race {
public static void main(String[] args) {
RabbitAndTurtle rabbit = new RabbitAndTurtle("Rabbit");
RabbitAndTurtle turtle= new RabbitAndTurtle("Turtle");
rabbit.start();
turtle.start();
}
}