多线程
(1)就是应用程序有多条执行路径。
进程:就是正在运行的程序。
线程:就是进程的执行路径,执行单元。
(2).如何使用多线程(掌握)
A:方式1 继承Thread类。
a:创建类继承Thread类
b:重写Thread类的run()方法。
run()方法里面才是封装线程的代码。
c:通过调用start()方法启动线程并调用run()方法。<<<start():第一,让线程启动。第二,自动调用run()方法。>>>
代码体现:
public class MyThread extends Thread {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(getName()+"---hello" + x);
}
}
}
main(){
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
my1.setName("用友");
my2.setName("金蝶");
my1.start();
my2.start();
}
...................
B:方式2 实现Runnable接口
a:创建一个类实现Runnable接口
b:重写run()方法
c:创建实现类对象,并把它作为参数传递给Thread类的构造方法,创建Thread对象
d:通过Thread的对象执行
代码体现:
public class MyRunnable implements Runnable{
@Override
public void run(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().class+"---"+i);
}
}
}
main(){
MyRunnable my = new MyRunnable();
Thread t1 = new Thread(my);
Thread t2 = new Thread(my);
t1.setName("乔峰");
t2.setName("慕容复");
t1.start();
t2.start();
}
1.多线程 2.共有资源同步多线程 3.解决错误输出(加锁) 4.均匀输出
<<<既然有了继承Thread类的方式,为什么还要有实现Runnable接口的方式?
* A:避免的单继承的局限性
* B:实现接口的方式,只创建了一个资源对象,更好的实现了数据和操作的分离。
* 一般我们选择第二种方式。>>>
<<< 实现了Runnable接口的类没有start()方法,而我们启动线程必须调用start()方法。
又由于,start()方法只有Thread类有。所以,我们就考虑这个把该类转换成Thread类。>>>
...................
(3)线程的随机性原理
多个程序其实是CPU的在做着高效切换执行的。
(4)线程的生命周期(面试题 画图自己补齐)
新建
就绪
运行
阻塞
死亡
(5)线程安全问题
A:卖票案例
B:为什么有问题
a:有共享数据
b:共享数据被多条语句操作
c:在多线程环境中
(6)线程安全问题的解决方案:
A:同步代码块
synchronized(锁对象)
{
被同步的代码
}
B:同步方法
把synchronized加在方法上。
一般推荐使用同步代码块。代码自己写一遍,然后粘贴到下面:
<<<同步代码块的锁对象是什么?
* 同步代码块的锁是任意对象。
*
* 同步方法:就是把锁加在方法上
* 格式:在方法上加synchronized关键字
*
* 同步方法的锁对象是谁? this对象
*
* 静态方法的锁对象是谁呢?
* 是当前类的字节码文件对象。
* 类名.class - Class类型的对象
*
* 以后我们用同步代码块还是同步方法呢?
* 被同步的内容越少越好,所以,一般使用同步代码块。
* 如果一个方法内部全部都被同步了,那么,可以考虑使用同步方法。>>>
public class TicketRunnable implements Runnable{
private static int tickets = 100;
private Object obj = new Object();
private Demo d = new Demo();
@Override
public void run(){
int x = 0;
while(true){
if(x%2 == 0){ //加这条语句就是为了展示两种线程安全结局方案
synchronized(this){ //因为方法上的锁对象是this.
if(tickets>0){
Thread.sleep(100); //这句必须try...catch...
System.out.println(Thread.currentThread()+"---"+tickets--);
}
}
}else{
check();//该方法用的是在方法上加synchronized;
}
}
}
}
..............................
(7)线程间的通信问题
学生类:
设置学生属性的类:
获取学生属性的类:
测试类:
面试题:sleep和wait()的区别?
wait():是Object类的方法,可以不用传递参数。释放锁对象。
sleep():是Thread类的静态方法,需要传递参数。**不释放锁对象。
public class SetStudent2 implements Runnable {
public class GetStudent2 implements Runnable {
public class Student2 {
public synchronized void set(Student2 s){
if (s.flag) {
try {
this.wait(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.name = s.name;
this.age = s.age;
//原因不在这,这里s从头到尾只有一个对象,所以用this和s是一样的。
//s.flag=true; s.notify();
this.flag = true;
this.notify();
}
public synchronized void get(Student2 s){
if (!this.flag) {
try {
this.wait(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(s.name+"---"+s.age);
this.flag = false;
this.notify();
}
}
(8)常见的方法
优先级
暂停线程
加入线程
守护线程
main方法本身就是一个线程。
*public final void setDaemon(boolean on):设置线程为守护线程,一旦前台(主线程),结束,守护线程就结束了。
DaemonDemo dd = new DaemonDemo();
Thread t1 = new Thread(dd);
t1.setDaemon(true);
public final void join():等待该线程终止。
* 一旦有join()线程,那么,当前线程必须等待,直到该线程结束。
JoinDemo pd = new JoinDemo();
Thread t1 = new Thread(pd);
t1.setName("林平之");
t1.join(); //需要处理异常
测试线程的优先级问题:
* 线程默认优先级是5。范围是1-10。
* public final int getPriority():获取线程优先级
* public final void setPriority(int newPriority):更改线程的优先级。
* 注意:优先级可以在一定的程度上,让线程获较多的执行机会。
PriorityDemo pd = new PriorityDemo();
Thread t1 = new Thread(pd);
t1.setName("林平之");
t1.setPriority(10);
public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
Thread.yield(); //在线程run()方法里使用。
(9)面试题:
sleep()和wait()的区别?
启动线程到底调用的是哪个方法?
run()和start()的区别?
同步的原理,以及有几种实现方式?
多线程记住这几个代码就好:
**4个窗口买100张票 数据无误
**学生类设置、获取信息交替
|